@@ -170,6 +170,7 @@ def upload_temperature(request): |
||
| 170 | 170 |
try: |
| 171 | 171 |
eqpt = ThermometerEquipmentInfo.objects.get(macid=macid, status=True) |
| 172 | 172 |
except ThermometerEquipmentInfo.DoesNotExist: |
| 173 |
+ ThermometerMeasureLogInfo.objects.create(point_id=eqpt.point_id, macid=macid, name=name, sex=sex, birth_stamp=birth_stamp, phone=phone, start_stamp=start_stamp, end_stamp=end_stamp, temperature=temperature, upload_temperature_info=request.POST, status=False) |
|
| 173 | 174 |
return response(ThermometerEquipmentStatusCode.THERMOMETER_EQUIPMENT_NOT_FOUND) |
| 174 | 175 |
|
| 175 | 176 |
try: |
@@ -196,3 +197,65 @@ def upload_temperature(request): |
||
| 196 | 197 |
}) |
| 197 | 198 |
|
| 198 | 199 |
return response() |
| 200 |
+ |
|
| 201 |
+ |
|
| 202 |
+def mqtt_upload_temperature(payload): |
|
| 203 |
+ # Received `{"mac":"A4DA324E7A63","pkt":"215","chg_sta":true,"bat":"100","raw_temp":"4697,4696,4697","sta":"0","alg_temp":"4697,4696,4697","alg_gstr":0,"ble_rssi":-21,"wifi_rssi":-68,"current_time":"2021-08-08 15:22:59"}` from `esp/240AC4D3C1AC` topic
|
|
| 204 |
+ # |
|
| 205 |
+ # {
|
|
| 206 |
+ # "mac": "A4DA324E7A63", # 体温贴 mac,固定 6 个字节,12 个字符 |
|
| 207 |
+ # "pkt": "215", # 广播包包序为 85,有效包序范围[1, 255] |
|
| 208 |
+ # "chg_sta": true, # 充电状态,true 充电,false 未充电 |
|
| 209 |
+ # "bat": "100", # 电量剩余 65%,有效电量范围[0, 100] |
|
| 210 |
+ # "raw_temp": "4697,4696,4697", # 三个原始温度数 |
|
| 211 |
+ # "sta": "0", # 算法返回状态 |
|
| 212 |
+ # "alg_temp": "4697,4696,4697", # 算法返回三个温度 |
|
| 213 |
+ # "alg_gstr": 0, # 算法手臂姿态 |
|
| 214 |
+ # "ble_rssi": -21, # 体温贴相对于底座的信号强度 |
|
| 215 |
+ # "wifi_rssi": -68, # 底座网络信号强度 |
|
| 216 |
+ # "current_time": "2021-08-08 15:22:59" # 底座接收到体温贴信息的实时时间 |
|
| 217 |
+ # } |
|
| 218 |
+ try: |
|
| 219 |
+ payload = json.loads(payload) |
|
| 220 |
+ except Exception: |
|
| 221 |
+ return |
|
| 222 |
+ |
|
| 223 |
+ macid = payload.get('mac', '')
|
|
| 224 |
+ macid = f'{macid[:2]}:{macid[2:4]}:{macid[4:6]}:{macid[6:8]}:{macid[8:10]}:{macid[10:12]}'
|
|
| 225 |
+ current_time = payload.get('current_time', '')
|
|
| 226 |
+ start_stamp = end_stamp = tc.string_to_timestamp(current_time) |
|
| 227 |
+ # raw_temp = payload.get('raw_temp', '')
|
|
| 228 |
+ alg_temp = payload.get('alg_temp', '')
|
|
| 229 |
+ |
|
| 230 |
+ # temp = raw_temp.split(',') + alg_temp.split(',')
|
|
| 231 |
+ temp = alg_temp.split(',')
|
|
| 232 |
+ temp = [int(t) for t in temp if t] |
|
| 233 |
+ |
|
| 234 |
+ if not temp: |
|
| 235 |
+ return |
|
| 236 |
+ |
|
| 237 |
+ temperature = max(temp) / 100 |
|
| 238 |
+ |
|
| 239 |
+ try: |
|
| 240 |
+ eqpt = ThermometerEquipmentInfo.objects.get(macid=macid, status=True) |
|
| 241 |
+ except ThermometerEquipmentInfo.DoesNotExist: |
|
| 242 |
+ ThermometerMeasureLogInfo.objects.create(macid=macid, start_stamp=start_stamp, end_stamp=end_stamp, temperature=temperature, temperature_src=ThermometerMeasureLogInfo.MQTT, upload_temperature_info=payload, status=False) |
|
| 243 |
+ return |
|
| 244 |
+ |
|
| 245 |
+ try: |
|
| 246 |
+ point = IsolationPointInfo.objects.get(point_id=eqpt.point_id, status=True) |
|
| 247 |
+ except IsolationPointInfo.DoesNotExist: |
|
| 248 |
+ return |
|
| 249 |
+ |
|
| 250 |
+ point_measure_ymd = tc.local_string(format='%Y-%m-%d') |
|
| 251 |
+ point_measure_window = point.current_measure_window |
|
| 252 |
+ |
|
| 253 |
+ eqpt.last_submit_at = tc.utc_datetime() |
|
| 254 |
+ eqpt.save() |
|
| 255 |
+ |
|
| 256 |
+ ThermometerMeasureLogInfo.objects.create(point_id=eqpt.point_id, macid=macid, start_stamp=start_stamp, end_stamp=end_stamp, temperature=temperature, temperature_src=ThermometerMeasureLogInfo.MQTT, upload_temperature_info=payload) |
|
| 257 |
+ |
|
| 258 |
+ if point_measure_window: |
|
| 259 |
+ ThermometerMeasureInfo.objects.update_or_create(point_id=eqpt.point_id, point_measure_ymd=point_measure_ymd, point_measure_window=point_measure_window, macid=macid, defaults={
|
|
| 260 |
+ 'temperature': temperature, |
|
| 261 |
+ }) |
@@ -0,0 +1,106 @@ |
||
| 1 |
+# -*- coding: utf-8 -*- |
|
| 2 |
+ |
|
| 3 |
+import logging |
|
| 4 |
+import random |
|
| 5 |
+import time |
|
| 6 |
+ |
|
| 7 |
+from django_six import CompatibilityBaseCommand |
|
| 8 |
+from paho.mqtt import client as mqtt_client |
|
| 9 |
+from api.eqpt_views import mqtt_upload_temperature |
|
| 10 |
+ |
|
| 11 |
+ |
|
| 12 |
+logger = logging.getLogger('console')
|
|
| 13 |
+ |
|
| 14 |
+ |
|
| 15 |
+# defined(PRORON_MQTT_DOMESTIC_SERVER) |
|
| 16 |
+# define MQTT_SERVER_TYPE MQTT_SERVER_TYPE_DOMAIN_NAME |
|
| 17 |
+# define MQTT_BROKER_URI "china.mqtt.protontek.com" /* Domestic server "47.100.92.19" */ |
|
| 18 |
+# define MQTT_USERNAME "proton" |
|
| 19 |
+# define MQTT_PASSWORD "proton123" |
|
| 20 |
+# define MQTT_PORT 1883 |
|
| 21 |
+broker = 'china.mqtt.protontek.com' |
|
| 22 |
+username = 'proton' |
|
| 23 |
+password = 'proton123' |
|
| 24 |
+port = 1883 |
|
| 25 |
+topic = 'esp/#' |
|
| 26 |
+client_id = f'python-mqtt-{random.randint(0, 1000)}'
|
|
| 27 |
+ |
|
| 28 |
+ |
|
| 29 |
+# MQTT连接 |
|
| 30 |
+def connect_mqtt(): |
|
| 31 |
+ def on_connect(client, userdata, flags, rc): |
|
| 32 |
+ if rc == 0: |
|
| 33 |
+ print('Connected to MQTT Broker')
|
|
| 34 |
+ else: |
|
| 35 |
+ print('Failed to connect, return code %d\n', rc)
|
|
| 36 |
+ # Set Connecting Client ID |
|
| 37 |
+ print(f'Connected to MQTT Broker by client_id `{client_id}`')
|
|
| 38 |
+ client = mqtt_client.Client(client_id) |
|
| 39 |
+ client.username_pw_set(username, password=password) |
|
| 40 |
+ client.on_connect = on_connect |
|
| 41 |
+ client.connect(broker, port) |
|
| 42 |
+ return client |
|
| 43 |
+ |
|
| 44 |
+ |
|
| 45 |
+# MQTT发布消息 |
|
| 46 |
+# from commands.management.commands.mqtt import publish_run |
|
| 47 |
+# publish_run() |
|
| 48 |
+def publish(client): |
|
| 49 |
+ msg_count = 0 |
|
| 50 |
+ while True: |
|
| 51 |
+ time.sleep(1) |
|
| 52 |
+ msg = f'messages: `{msg_count}`'
|
|
| 53 |
+ result = client.publish(topic, msg) |
|
| 54 |
+ # result: [0, 1] |
|
| 55 |
+ status = result[0] |
|
| 56 |
+ if status == 0: |
|
| 57 |
+ print(f'Send `{msg}` to topic `{topic}`')
|
|
| 58 |
+ else: |
|
| 59 |
+ print(f'Failed to send message to topic {topic}')
|
|
| 60 |
+ msg_count += 1 |
|
| 61 |
+ |
|
| 62 |
+ |
|
| 63 |
+def publish_run(): |
|
| 64 |
+ client = connect_mqtt() |
|
| 65 |
+ client.loop_start() |
|
| 66 |
+ publish(client) |
|
| 67 |
+ |
|
| 68 |
+ |
|
| 69 |
+# MQTT订阅消息 |
|
| 70 |
+def subscribe(client: mqtt_client): |
|
| 71 |
+ def on_message(client, userdata, msg): |
|
| 72 |
+ # Received `{"mac":"A4DA324E7A63","pkt":"215","chg_sta":true,"bat":"100","raw_temp":"4697,4696,4697","sta":"0","alg_temp":"4697,4696,4697","alg_gstr":0,"ble_rssi":-21,"wifi_rssi":-68,"current_time":"2021-08-08 15:22:59"}` from `esp/240AC4D3C1AC` topic
|
|
| 73 |
+ # |
|
| 74 |
+ # {
|
|
| 75 |
+ # "mac": "A4DA324E7A63", # 体温贴 mac,固定 6 个字节,12 个字符 |
|
| 76 |
+ # "pkt": "215", # 广播包包序为 85,有效包序范围[1, 255] |
|
| 77 |
+ # "chg_sta": true, # 充电状态,true 充电,false 未充电 |
|
| 78 |
+ # "bat": "100", # 电量剩余 65%,有效电量范围[0, 100] |
|
| 79 |
+ # "raw_temp": "4697,4696,4697", # 三个原始温度数 |
|
| 80 |
+ # "sta": "0", # 算法返回状态 |
|
| 81 |
+ # "alg_temp": "4697,4696,4697", # 算法返回三个温度 |
|
| 82 |
+ # "alg_gstr": 0, # 算法手臂姿态 |
|
| 83 |
+ # "ble_rssi": -21, # 体温贴相对于底座的信号强度 |
|
| 84 |
+ # "wifi_rssi": -68, # 底座网络信号强度 |
|
| 85 |
+ # "current_time": "2021-08-08 15:22:59" # 底座接收到体温贴信息的实时时间 |
|
| 86 |
+ # } |
|
| 87 |
+ payload = msg.payload.decode() |
|
| 88 |
+ print(f'Received `{payload}` from `{msg.topic}` topic')
|
|
| 89 |
+ mqtt_upload_temperature(payload) |
|
| 90 |
+ |
|
| 91 |
+ client.subscribe(topic) |
|
| 92 |
+ client.on_message = on_message |
|
| 93 |
+ |
|
| 94 |
+ |
|
| 95 |
+def subscribe_run(): |
|
| 96 |
+ client = connect_mqtt() |
|
| 97 |
+ subscribe(client) |
|
| 98 |
+ client.loop_forever() |
|
| 99 |
+ |
|
| 100 |
+ |
|
| 101 |
+class Command(CompatibilityBaseCommand): |
|
| 102 |
+ def handle(self, *args, **options): |
|
| 103 |
+ |
|
| 104 |
+ logger.info('MQTT client is dealing')
|
|
| 105 |
+ |
|
| 106 |
+ subscribe_run() |
@@ -22,8 +22,8 @@ class ThermometerMeasureInfoAdmin(ReadOnlyModelAdmin, admin.ModelAdmin): |
||
| 22 | 22 |
|
| 23 | 23 |
|
| 24 | 24 |
class ThermometerMeasureLogInfoAdmin(ReadOnlyModelAdmin, admin.ModelAdmin): |
| 25 |
- list_display = ('point_id', 'macid', 'sn', 'name', 'sex', 'birth_stamp', 'phone', 'start_stamp', 'end_stamp', 'temperature', 'status', 'updated_at', 'created_at')
|
|
| 26 |
- list_filter = ('point_id', 'status')
|
|
| 25 |
+ list_display = ('point_id', 'macid', 'sn', 'name', 'sex', 'birth_stamp', 'phone', 'start_stamp', 'end_stamp', 'temperature', 'temperature_src', 'status', 'updated_at', 'created_at')
|
|
| 26 |
+ list_filter = ('point_id', 'temperature_src', 'status')
|
|
| 27 | 27 |
|
| 28 | 28 |
|
| 29 | 29 |
admin.site.register(IsolationPointInfo, IsolationPointInfoAdmin) |
@@ -0,0 +1,18 @@ |
||
| 1 |
+# Generated by Django 3.2.6 on 2021-08-08 11:03 |
|
| 2 |
+ |
|
| 3 |
+from django.db import migrations, models |
|
| 4 |
+ |
|
| 5 |
+ |
|
| 6 |
+class Migration(migrations.Migration): |
|
| 7 |
+ |
|
| 8 |
+ dependencies = [ |
|
| 9 |
+ ('equipment', '0004_auto_20210712_0035'),
|
|
| 10 |
+ ] |
|
| 11 |
+ |
|
| 12 |
+ operations = [ |
|
| 13 |
+ migrations.AddField( |
|
| 14 |
+ model_name='thermometermeasureloginfo', |
|
| 15 |
+ name='temperature_src', |
|
| 16 |
+ field=models.IntegerField(choices=[(1, '接口回调'), (2, 'MQTT')], default=1, help_text='用户体温来源', verbose_name='temperature_src'), |
|
| 17 |
+ ), |
|
| 18 |
+ ] |
@@ -148,6 +148,14 @@ class ThermometerMeasureInfo(BaseModelMixin): |
||
| 148 | 148 |
|
| 149 | 149 |
|
| 150 | 150 |
class ThermometerMeasureLogInfo(BaseModelMixin): |
| 151 |
+ CALLBACK = 1 |
|
| 152 |
+ MQTT = 2 |
|
| 153 |
+ |
|
| 154 |
+ TEMPERATURE_SRC_TUPLE = ( |
|
| 155 |
+ (CALLBACK, '接口回调'), |
|
| 156 |
+ (MQTT, 'MQTT'), |
|
| 157 |
+ ) |
|
| 158 |
+ |
|
| 151 | 159 |
point_id = models.CharField(_('point_id'), max_length=32, blank=True, null=True, help_text='隔离点唯一标识', db_index=True)
|
| 152 | 160 |
|
| 153 | 161 |
macid = models.CharField(_('macid'), max_length=32, blank=True, null=True, help_text='设备号')
|
@@ -163,6 +171,8 @@ class ThermometerMeasureLogInfo(BaseModelMixin): |
||
| 163 | 171 |
|
| 164 | 172 |
temperature = models.FloatField(_('temperature'), default=0, help_text='用户体温')
|
| 165 | 173 |
|
| 174 |
+ temperature_src = models.IntegerField(_('temperature_src'), choices=TEMPERATURE_SRC_TUPLE, default=CALLBACK, help_text='用户体温来源')
|
|
| 175 |
+ |
|
| 166 | 176 |
upload_temperature_info = models.TextField(_('upload_temperature_info'), blank=True, null=True, help_text='测温结果上传信息')
|
| 167 | 177 |
|
| 168 | 178 |
class Meta: |
@@ -2,6 +2,7 @@ StatusCode==1.0.0 |
||
| 2 | 2 |
furl==2.1.2 |
| 3 | 3 |
jsonfield==3.1.0 |
| 4 | 4 |
mysqlclient==2.0.3 |
| 5 |
+paho-mqtt==1.5.1 |
|
| 5 | 6 |
pysnippets==1.1.4 |
| 6 | 7 |
requests==2.25.1 |
| 7 | 8 |
rlog==0.3 |
@@ -1,3 +1,3 @@ |
||
| 1 |
-ipdb==0.13.3 |
|
| 2 |
-ipython==7.18.1 |
|
| 1 |
+ipdb==0.13.9 |
|
| 2 |
+ipython==7.26.0 |
|
| 3 | 3 |
uwsgi==2.0.19.1 |
@@ -1,2 +1,2 @@ |
||
| 1 |
-isort==5.4.2 |
|
| 2 |
-pycodestyle==2.6.0 |
|
| 1 |
+isort==5.9.3 |
|
| 2 |
+pycodestyle==2.7.0 |
@@ -305,7 +305,7 @@ DJANGO_SHORT_URL_REDIRECT_URL = '' |
||
| 305 | 305 |
|
| 306 | 306 |
# Django-We Settings |
| 307 | 307 |
DJANGO_WE_QUOTE_OR_NOT = True |
| 308 |
-DJANGO_WE_MODEL_DISPLAY_OR_NOT = True |
|
| 308 |
+DJANGO_WE_MODEL_DISPLAY_OR_NOT = False |
|
| 309 | 309 |
# Enable Cookie or not |
| 310 | 310 |
# DJANGO_WE_BASE_REDIRECT_SET_COOKIE = False |
| 311 | 311 |
# DJANGO_WE_USERINFO_REDIRECT_SET_COOKIE = True |