feat: sensor readings with JWT auth, OLED display, data_destination_url
This commit is contained in:
@@ -290,7 +290,7 @@ def run():
|
||||
if caps.get('has_nfc'):
|
||||
from provisioning_nfc import run_provisioning_nfc
|
||||
_show(['PROVISIONING', 'NFC mode', '', 'Tap writer badge', ''])
|
||||
cfg = run_provisioning_nfc(_nfc)
|
||||
cfg = run_provisioning_nfc()
|
||||
else:
|
||||
from provisioning_server import run_provisioning
|
||||
wlan_sta = network.WLAN(network.STA_IF)
|
||||
@@ -335,11 +335,11 @@ def run():
|
||||
|
||||
if node_type == 'sensor':
|
||||
from node_sensor import run_sensor
|
||||
run_sensor(cfg, caps)
|
||||
run_sensor(cfg, caps, checkin_result['token'])
|
||||
|
||||
elif node_type == 'relay':
|
||||
from node_relay import run_relay
|
||||
run_relay(cfg, caps)
|
||||
run_relay(cfg, caps, checkin_result['token'])
|
||||
|
||||
else:
|
||||
print('[operational] unknown node_type:', node_type)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"node_type": "sensor",
|
||||
"node_label": "node-01",
|
||||
"identity_iot_url": "https://api.yourhost.com/API/V1/identity_layer/identity_iot/",
|
||||
"data_destination_url": "",
|
||||
"data_destination_url": "https://api.parta.app/API/V1/identity_iot/",
|
||||
"pinout": {
|
||||
"i2c0_sda": 4,
|
||||
"i2c0_scl": 5,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import utime
|
||||
|
||||
|
||||
def run_relay(cfg, caps):
|
||||
def run_relay(cfg, caps, jwt_token=''):
|
||||
"""Main loop for relay node type. Called from boot_manager."""
|
||||
print('[relay] starting — relay:', caps.get('has_relay'))
|
||||
|
||||
|
||||
140
node_sensor.py
140
node_sensor.py
@@ -5,16 +5,140 @@
|
||||
# ============================================================+
|
||||
|
||||
import utime
|
||||
import ujson
|
||||
import machine
|
||||
|
||||
try:
|
||||
import uurequests as requests
|
||||
except ImportError:
|
||||
import urequests as requests
|
||||
|
||||
from identity_iot_aes import aes_cbc_encrypt, aes_cbc_decrypt
|
||||
|
||||
|
||||
def run_sensor(cfg, caps):
|
||||
"""Main loop for sensor node type. Called from boot_manager."""
|
||||
print('[sensor] starting — sensor:', caps.get('has_sensor'))
|
||||
def _read_internal_temp():
|
||||
sensor = machine.ADC(4)
|
||||
reading = sensor.read_u16()
|
||||
voltage = reading * 3.3 / 65535
|
||||
temp_c = 27 - (voltage - 0.706) / 0.001721
|
||||
return round(temp_c, 2)
|
||||
|
||||
# TODO: read DHT22 / other sensor
|
||||
# TODO: POST readings to backend via AES channel
|
||||
# TODO: polling interval from cfg
|
||||
|
||||
def _read_dht22(dht_sensor):
|
||||
try:
|
||||
dht_sensor.measure()
|
||||
return {
|
||||
'temperature': dht_sensor.temperature(),
|
||||
'humidity': dht_sensor.humidity(),
|
||||
}
|
||||
except Exception as e:
|
||||
print('[sensor] DHT22 read error:', e)
|
||||
return None
|
||||
|
||||
|
||||
def _show_reading(reading, label):
|
||||
try:
|
||||
import boot_manager
|
||||
temp = reading.get('temperature', reading.get('temp_internal', '--'))
|
||||
hum = reading.get('humidity')
|
||||
boot_manager._show([
|
||||
'Identity IoT',
|
||||
label or 'sensor',
|
||||
'Temp: ' + str(temp) + 'C',
|
||||
'Hum: ' + (str(hum) + '%' if hum is not None else '--'),
|
||||
'',
|
||||
])
|
||||
except Exception as e:
|
||||
print('[sensor] display error:', e)
|
||||
|
||||
|
||||
def _post_reading(cfg, key, iv, payload, jwt_token=''):
|
||||
url = cfg.get('data_destination_url', '')
|
||||
if not url:
|
||||
print('[sensor] no data_destination_url configured')
|
||||
return False
|
||||
try:
|
||||
body = ujson.dumps({'data': aes_cbc_encrypt(ujson.dumps(payload), key, iv)})
|
||||
resp = requests.post(
|
||||
url,
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + jwt_token,
|
||||
},
|
||||
data=body,
|
||||
timeout=10,
|
||||
)
|
||||
raw = resp.text
|
||||
resp.close()
|
||||
outer = ujson.loads(raw)
|
||||
clear = aes_cbc_decrypt(outer['data'], key, iv)
|
||||
result = ujson.loads(clear)
|
||||
if result.get('status') == 'ok':
|
||||
print('[sensor] reading posted ok')
|
||||
return True
|
||||
print('[sensor] post error:', result.get('code', 'unknown'))
|
||||
return False
|
||||
except Exception as e:
|
||||
print('[sensor] post failed:', e)
|
||||
return False
|
||||
|
||||
|
||||
def run_sensor(cfg, caps, jwt_token=''):
|
||||
print('[sensor] starting — has_sensor:', caps.get('has_sensor'))
|
||||
|
||||
key = cfg['comm_key'].encode() if isinstance(cfg['comm_key'], str) else cfg['comm_key']
|
||||
iv = cfg['comm_iv'].encode() if isinstance(cfg['comm_iv'], str) else cfg['comm_iv']
|
||||
|
||||
poll_interval = int(cfg.get('poll_interval', 60))
|
||||
temp_min = cfg.get('temp_min')
|
||||
temp_max = cfg.get('temp_max')
|
||||
node_id = cfg.get('node_id', '')
|
||||
tenant_id = cfg.get('tenant_id', '')
|
||||
label = cfg.get('node_label', '')
|
||||
|
||||
dht_sensor = None
|
||||
if caps.get('has_sensor'):
|
||||
try:
|
||||
import dht
|
||||
from machine import Pin
|
||||
dht_pin = cfg.get('pinout', {}).get('dht_pin', 15)
|
||||
dht_sensor = dht.DHT22(Pin(dht_pin))
|
||||
except Exception as e:
|
||||
print('[sensor] DHT22 init error:', e)
|
||||
|
||||
while True:
|
||||
print('[sensor] polling...')
|
||||
utime.sleep(10)
|
||||
reading = {}
|
||||
reading['temp_internal'] = _read_internal_temp()
|
||||
|
||||
if dht_sensor:
|
||||
dht_data = _read_dht22(dht_sensor)
|
||||
if dht_data:
|
||||
reading['temperature'] = dht_data['temperature']
|
||||
reading['humidity'] = dht_data['humidity']
|
||||
|
||||
print('[sensor] reading:', reading)
|
||||
_show_reading(reading, label)
|
||||
|
||||
should_post = True
|
||||
if temp_min is not None or temp_max is not None:
|
||||
temp = reading.get('temperature', reading.get('temp_internal'))
|
||||
in_range = True
|
||||
if temp_min is not None and temp < float(temp_min):
|
||||
in_range = False
|
||||
if temp_max is not None and temp > float(temp_max):
|
||||
in_range = False
|
||||
if in_range:
|
||||
should_post = False
|
||||
|
||||
if should_post:
|
||||
payload = {
|
||||
'request': 'iot_node_reading',
|
||||
'node_id': node_id,
|
||||
'tenant_id': tenant_id,
|
||||
'label': label,
|
||||
'reading': reading,
|
||||
'ts': utime.time(),
|
||||
}
|
||||
_post_reading(cfg, key, iv, payload, jwt_token)
|
||||
|
||||
utime.sleep(poll_interval)
|
||||
|
||||
Reference in New Issue
Block a user