From 641fe8f6046c50d312394c281ab3fcc9e8f59a14 Mon Sep 17 00:00:00 2001 From: Craig Oates Date: Wed, 8 Jan 2020 21:08:07 +0000 Subject: [PATCH] add device status-update logging. --- app/api.py | 5 +- app/build_database.py | 35 ++++++++++++- app/models/devices.py | 82 +++++++++++++++++++++++++++++++ app/readings.db | Bin 16384 -> 40960 bytes app/readings.db-journal | Bin 0 -> 4616 bytes app/services/get_services.py | 4 ++ app/services/post_services.py | 90 +++++++++++++++++++++++++++++++--- app/swagger.yml | 59 ++++++++++++++++++++-- 8 files changed, 261 insertions(+), 14 deletions(-) create mode 100644 app/models/devices.py create mode 100644 app/readings.db-journal diff --git a/app/api.py b/app/api.py index a7a53a8..ceb9ba1 100644 --- a/app/api.py +++ b/app/api.py @@ -10,7 +10,10 @@ These functions are acting as very light controllers essentially. ''' def post_a_reading(light_meter, the_reading): - return post_services.add_latest_reading(light_meter,the_reading) + return post_services.add_latest_reading(light_meter, the_reading) + +def post_a_status_change(device, the_status_change): + return post_services.log_status_change(device, the_status_change) def get_latest(light_meter): return get_services.get_latest_reading(light_meter) diff --git a/app/build_database.py b/app/build_database.py index 059a07d..c88772e 100644 --- a/app/build_database.py +++ b/app/build_database.py @@ -2,6 +2,7 @@ import os from datetime import datetime from config import db from models.meters import Meter1, Meter2, Meter3 +from models.devices import Device1, Device2, Device3, Device4, Device5, Device6 def get_timestamp(): return datetime.now().strftime(("%Y-%m-%d %H:%M:%S")) @@ -10,6 +11,12 @@ def get_timestamp(): READINGS1 =[ {"time":datetime.now(), "reading": 0} ] READINGS2 =[ {"time":datetime.now(), "reading": 0} ] READINGS3 =[ {"time":datetime.now(), "reading": 0} ] +DEVICE1 = [ {"time":datetime.now(), "status": "off"} ] +DEVICE2 = [ {"time":datetime.now(), "status": "off"} ] +DEVICE3 = [ {"time":datetime.now(), "status": "off"} ] +DEVICE4 = [ {"time":datetime.now(), "status": "off"} ] +DEVICE5 = [ {"time":datetime.now(), "status": "off"} ] +DEVICE6 = [ {"time":datetime.now(), "status": "off"} ] # Deletes the database if it already exists if os.path.exists("readings.db"): @@ -28,9 +35,35 @@ for info in READINGS2: r = Meter2(time=info.get("time"), reading=info.get("reading")) db.session.add(r) -# Iterates over the READINGS3 structure and populates the datebase +# Iterates over the READINGS3 structure and populates the datebase. for info in READINGS3: r = Meter3(time=info.get("time"), reading=info.get("reading")) db.session.add(r) + +# These are the light-meters in Ritherdon. +for info in DEVICE1: + r = Device1(time=info.get("time"), status=info.get("status")) + db.session.add(r) + +for info in DEVICE2: + r = Device2(time=info.get("time"), status=info.get("status")) + db.session.add(r) + +for info in DEVICE3: + r = Device3(time=info.get("time"), status=info.get("status")) + db.session.add(r) + +# These are the relays in the gallery. +for info in DEVICE4: + r = Device4(time=info.get("time"), status=info.get("status")) + db.session.add(r) + +for info in DEVICE5: + r = Device5(time=info.get("time"), status=info.get("status")) + db.session.add(r) + +for info in DEVICE6: + r = Device6(time=info.get("time"), status=info.get("status")) + db.session.add(r) db.session.commit() diff --git a/app/models/devices.py b/app/models/devices.py new file mode 100644 index 0000000..25c2c35 --- /dev/null +++ b/app/models/devices.py @@ -0,0 +1,82 @@ +from datetime import datetime +from config import db, ma + +''' +Note on Duplication Levels +====================================================================== +While the code in this file seems very duplicated, it is just the +result of using SQL-Alchemy (ORM) and the repetitive nature of the +project as a whole. At the time of writing, the expected amount of +devices is six. They must keep their info. separate from each other. +This means a table in the database for each device. This is the main +cause for the repetitive/duplicated code. Because this project has +fixed requirements, the hard-coded nature is a trade-off because of +this. If the project increases the amount of devices it uses, this +will probably need to be refactored. +''' + +class Device1(db.Model): + __tablename__ = "device1" + id = db.Column(db.Integer, primary_key=True) + time = db.Column(db.DateTime, default=datetime.utcnow) + status = db.Column(db.String) + +class Device1Schema(ma.ModelSchema): + class Meta: + model = Device1 + sqla_session = db.session + +class Device2(db.Model): + __tablename__ = "device2" + id = db.Column(db.Integer, primary_key=True) + time = db.Column(db.DateTime, default=datetime.utcnow) + status = db.Column(db.String) + +class Device2Schema(ma.ModelSchema): + class Meta: + model = Device2 + sqla_session = db.session + +class Device3(db.Model): + __tablename__ = "device3" + id = db.Column(db.Integer, primary_key=True) + time = db.Column(db.DateTime, default=datetime.utcnow) + status = db.Column(db.String) + +class Device3Schema(ma.ModelSchema): + class Meta: + model = Device1 + sqla_session = db.session + +class Device4(db.Model): + __tablename__ = "device4" + id = db.Column(db.Integer, primary_key=True) + time = db.Column(db.DateTime, default=datetime.utcnow) + status = db.Column(db.String) + +class Device4Schema(ma.ModelSchema): + class Meta: + model = Device1 + sqla_session = db.session + +class Device5(db.Model): + __tablename__ = "device5" + id = db.Column(db.Integer, primary_key=True) + time = db.Column(db.DateTime, default=datetime.utcnow) + status = db.Column(db.String) + +class Device5Schema(ma.ModelSchema): + class Meta: + model = Device1 + sqla_session = db.session + +class Device6(db.Model): + __tablename__ = "device6" + id = db.Column(db.Integer, primary_key=True) + time = db.Column(db.DateTime, default=datetime.utcnow) + status = db.Column(db.String) + +class Device6Schema(ma.ModelSchema): + class Meta: + model = Device1 + sqla_session = db.session diff --git a/app/readings.db b/app/readings.db index 4cb822be5e6b16b6b29108111feb506e5badf0d1..b555a9763b8c07e41230206af32bddca510c7402 100644 GIT binary patch literal 40960 zcmeI&-D=uk9LMoQZGEZMjUALy7*Eeyn35M`)uXvCY%=RMX9qoWGY(<4V6&Zx$Zlfy zvTG^qO2!^d1xK=4A+?izAB>5QG5?>Rkb^(TySMe8>xk~fpx<_dsXS0rRe36eq9|#( zq~tOiNx2c5eUNK)Zu@VWX(g{!GVhd}JFzDdmu}nraw*ZfJQJ_%GjY)C z9HtIO34Z{~t7Rnv0$8C3i2DN+ya0tnK!8H%0XF>sOfP^L4+vm}9$>>C!0-YXn*jlg z&;!K$0dy~bz7Y^W4?Dmx8sFL7om~Ze$8`p#_a6JByf?Q@^?}pw^v*xcu9x6zU>Nb0 zH>RbGsK5MD`nM~u`pWCm@_NKyekuD~m7nzHYWAlhUkn5gKmY**5I_I{1Q0*~0R#|O zQ-Q~7OsOUe&Cqh1p3_P~FIOz9qLuPmu~;gV>HpXC#1b0;1Q0*~0R#|0009ILKmdU` zft&mPvO)hphs7oW2q1s}0tg_000IagfB*t(DzKpcHz)mnH2Yo2US)sC6$1eT5I_I{ z1Q0*~0R#|0009J6D6k)u&+R`lG`*bDwVYlS`cXwIRIH=CHXRq;u87E89^SCa`TpeL ze|eDLhyTl_JcxJy|4R1%EBtemLI42-5I_I{1Q0*~0R#|00DvSV^3+8D0R#|0009ILKmY**5I|sc0t@LoI{{L^+ C?V!^D delta 121 zcmZoTz|_#dI6+#Fg@J(qgkgYrqK>gJ3xl446)#YTnXj3FzmcDbuX(eefFR%IX1*Lj hK~n`IV=H50D^n9a3j-rd1Cvbx@A)xA&9RDF008h~7ZCse diff --git a/app/readings.db-journal b/app/readings.db-journal new file mode 100644 index 0000000000000000000000000000000000000000..290d5f9ed7c2d6179d082918513d1188f9659c7f GIT binary patch literal 4616 zcmeI$F%E+;3VA&~o30c+(-- Posts a reading from one of the project's light meters and store it in the database. @@ -54,7 +54,7 @@ paths: time: type: string format: date-time - example: 2019-10-19 17:04:57.880010 + example: 2019-10-19 17:04:57 description: >- The date and time the reading was taken. Make sure you use the UTC time format. This is because the @@ -72,11 +72,60 @@ paths: description: >- The reading was successfully added to the database. + /status/update/{device}: + post: + operationId: api.post_a_status_change + tags: + - Log Device Status Change + summary: >- + Logs a change in the status of the specified device. + description: >- + This is mostly to check if the devices included in this project + are turned on, off or an error has occured and they are + unreachable/crashed. + parameters: + - name: device + in: path + description: >- + The Id. of the device with the change in status. 1, 2 and 3 + refer to the light-meters in Ritherdon and 4, 5 and 6 + refer to the relays in the gallery. The pairing of each + meter and relay is as follows: 1->4, 2->5 and 3->6. + type: integer + required: True + - name: the_status_change + in: body + description: >- + The status change and the time the change occurred. + required: True + schema: + type: object + properties: + time: + type: string + format: date-time + example: 2019-10-19 17:04:57 + description: >- + The date and time the change in status occurred. Make + sure to use the U.T.C. time format. This is because + the A.P.I. has made a design decision to standardise + on it. + status: + type: string + example: "on" + description: >- + The current status of the device you would like to log. + The two status types are "on" and "off". + responses: + 201: + description: >- + The status update was successfully added to the database. + /readings/latest/{light_meter}: get: operationId: api.get_latest tags: - - Request Readings + - Request Light-Meter Readings summary: >- Returns the latest reading from the specified light meter. description: >- @@ -129,7 +178,7 @@ paths: get: operationId: api.get_all_readings tags: - - Request Readings + - Request Light-Meter Readings summary: >- Returns every reading taken by the specified light meter. description: >- @@ -180,7 +229,7 @@ paths: get: operationId: api.get_all_readings_for_every_meter tags: - - Request Readings + - Request Light-Meter Readings summary: >- Returns every reading taken by every light meter in the project.