import network, time, ujson, machine, dht
from umqtt.simple import MQTTClient
from machine import Pin
SSID = "Wokwi-GUEST"
BROKER = "broker.hivemq.com"
GROUP = "ia-z41"
DEVICE = "node-09"
CLIENT_ID = "ia-edge09-" + machine.unique_id().hex()
T_ALERT = "ia/{}/{}/alerts".format(GROUP, DEVICE).encode()
T_BEAT = "ia/{}/{}/heartbeat".format(GROUP, DEVICE).encode()
ALPHA = 0.10
K = 3.0
WARMUP = 30
MIN_STD = 0.5
state = {
"temp": {"mean": None, "var": 0.0, "n": 0},
"hum": {"mean": None, "var": 0.0, "n": 0}
}
sensor = dht.DHT22(Pin(15))
def connect_mqtt():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
wlan.connect(SSID, "")
while not wlan.isconnected():
time.sleep(0.5)
client = MQTTClient(CLIENT_ID, BROKER, port=1883, keepalive=60)
client.connect()
return client
def process_metric(metric_name, value):
s = state[metric_name]
if s["mean"] is None:
s["mean"] = value
s["n"] += 1
return False, 0.0
std = s["var"] ** 0.5
if std < MIN_STD: std = MIN_STD
z = (value - s["mean"]) / std
s["n"] += 1
is_anom = (s["n"] > WARMUP) and (abs(z) > K)
diff = value - s["mean"]
s["mean"] = s["mean"] + ALPHA * diff
s["var"] = (1 - ALPHA) * (s["var"] + ALPHA * diff * diff)
return is_anom, z
client = connect_mqtt()
print("Мережа OK. Очікування розігріву (60 сек)...")
last_beat = time.time()
while True:
try:
sensor.measure()
t = sensor.temperature()
h = sensor.humidity()
except OSError:
time.sleep(2)
continue
t_alarm, t_z = process_metric("temp", t)
h_alarm, h_z = process_metric("hum", h)
now = time.time()
if t_alarm or h_alarm:
broken = []
if t_alarm: broken.append("temperature")
if h_alarm: broken.append("humidity")
msg = {
"ts": now, "broken_signal": broken,
"temperature": t, "t_z": round(t_z, 2),
"humidity": h, "h_z": round(h_z, 2),
"type": "anomaly"
}
try:
client.publish(T_ALERT, ujson.dumps(msg))
print("ALERT ->", msg)
except Exception:
try:
client = connect_mqtt()
client.publish(T_ALERT, ujson.dumps(msg))
print("ALERT (відправлено після відновлення зв'язку) ->", msg)
except: pass
if now - last_beat >= 60:
beat_msg = {
"ts": now,
"t_mean": round(state["temp"]["mean"] or 0, 2),
"h_mean": round(state["hum"]["mean"] or 0, 2)
}
try:
client.publish(T_BEAT, ujson.dumps(beat_msg))
print("HEARTBEAT ->", beat_msg)
last_beat = now
except Exception:
try:
client = connect_mqtt()
client.publish(T_BEAT, ujson.dumps(beat_msg))
print("HEARTBEAT (після відновлення) ->", beat_msg)
last_beat = now
except: pass
time.sleep(2)