Dateien nach "pg26" hochladen

work in progress implementation of new framework
This commit is contained in:
2025-10-30 00:20:18 +00:00
parent 87cfa83af9
commit bd19860ae7
5 changed files with 374 additions and 0 deletions

12
pg26/boot.py Normal file
View File

@@ -0,0 +1,12 @@
# This file is executed on every boot (including wake-boot from deepsleep)
#import esp
#esp.osdebug(None)
#import webrepl
#webrepl.start()
import uos, machine
#uos.dupterm(None, 1) # disable REPL on UART(0)
machine.freq(240000000) #max freq
import gc
#import webrepl
#webrepl.start()
gc.collect()

16
pg26/main.py Normal file
View File

@@ -0,0 +1,16 @@
import pnd
import _thread
import time
print(pnd.cfg.tasks.gc_tasks)
## init pundo system
runtime = pnd.rt()
runtime.init(0)
## run backgroundtasks
_thread.start_new_thread(runtime.backgroundTask, ())
## run main Task
runtime.run()

202
pg26/mqtt.py Normal file
View File

@@ -0,0 +1,202 @@
#!/usr/bin/env python
#
# Copyright (c) 2019, Pycom Limited.
#
# This software is licensed under the GNU GPL version 3 or any
# later version, with permitted additional terms. For more information
# see the Pycom Licence v1.0 document supplied with this file, or
# available at https://www.pycom.io/opensource/licensing
#
import usocket as socket
import ustruct as struct
from ubinascii import hexlify
class MQTTException(Exception):
pass
class MQTTClient:
def __init__(self, client_id, server, port=0, user=None, password=None, keepalive=0,
ssl=False, ssl_params={}):
if port == 0:
port = 8883 if ssl else 1883
self.client_id = client_id
self.sock = None
self.addr = socket.getaddrinfo(server, port)[0][-1]
self.ssl = ssl
self.ssl_params = ssl_params
self.pid = 0
self.cb = None
self.user = user
self.pswd = password
self.keepalive = keepalive
self.lw_topic = None
self.lw_msg = None
self.lw_qos = 0
self.lw_retain = False
def _send_str(self, s):
self.sock.write(struct.pack("!H", len(s)))
self.sock.write(s)
def _recv_len(self):
n = 0
sh = 0
while 1:
b = self.sock.read(1)[0]
n |= (b & 0x7f) << sh
if not b & 0x80:
return n
sh += 7
def set_callback(self, f):
self.cb = f
def set_last_will(self, topic, msg, retain=False, qos=0):
assert 0 <= qos <= 2
assert topic
self.lw_topic = topic
self.lw_msg = msg
self.lw_qos = qos
self.lw_retain = retain
def connect(self, clean_session=True):
self.sock = socket.socket()
self.sock.connect(self.addr)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if self.ssl:
import ussl
self.sock = ussl.wrap_socket(self.sock, **self.ssl_params)
msg = bytearray(b"\x10\0\0\x04MQTT\x04\x02\0\0")
msg[1] = 10 + 2 + len(self.client_id)
msg[9] = clean_session << 1
if self.user is not None:
msg[1] += 2 + len(self.user) + 2 + len(self.pswd)
msg[9] |= 0xC0
if self.keepalive:
assert self.keepalive < 65536
msg[10] |= self.keepalive >> 8
msg[11] |= self.keepalive & 0x00FF
if self.lw_topic:
msg[1] += 2 + len(self.lw_topic) + 2 + len(self.lw_msg)
msg[9] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3
msg[9] |= self.lw_retain << 5
self.sock.write(msg)
#print(hex(len(msg)), hexlify(msg, ":"))
self._send_str(self.client_id)
if self.lw_topic:
self._send_str(self.lw_topic)
self._send_str(self.lw_msg)
if self.user is not None:
self._send_str(self.user)
self._send_str(self.pswd)
resp = self.sock.read(4)
assert resp[0] == 0x20 and resp[1] == 0x02
if resp[3] != 0:
raise MQTTException(resp[3])
return resp[2] & 1
def disconnect(self):
##self.sock.write(b"\xe0\0")
self.sock.close()
def ping(self):
self.sock.write(b"\xc0\0")
def publish(self, topic, msg, retain=False, qos=0):
pkt = bytearray(b"\x30\0\0\0")
pkt[0] |= qos << 1 | retain
sz = 2 + len(topic) + len(msg)
if qos > 0:
sz += 2
assert sz < 2097152
i = 1
while sz > 0x7f:
pkt[i] = (sz & 0x7f) | 0x80
sz >>= 7
i += 1
pkt[i] = sz
#print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt, i + 1)
self._send_str(topic)
if qos > 0:
self.pid += 1
pid = self.pid
struct.pack_into("!H", pkt, 0, pid)
self.sock.write(pkt, 2)
self.sock.write(msg)
if qos == 1:
while 1:
op = self.wait_msg()
if op == 0x40:
sz = self.sock.read(1)
assert sz == b"\x02"
rcv_pid = self.sock.read(2)
rcv_pid = rcv_pid[0] << 8 | rcv_pid[1]
if pid == rcv_pid:
return
elif qos == 2:
assert 0
def subscribe(self, topic, qos=0):
assert self.cb is not None, "Subscribe callback is not set"
pkt = bytearray(b"\x82\0\0\0")
self.pid += 1
struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
#print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt)
self._send_str(topic)
self.sock.write(qos.to_bytes(1, "little"))
while 1:
op = self.wait_msg()
if op == 0x90:
resp = self.sock.read(4)
#print(resp)
assert resp[1] == pkt[2] and resp[2] == pkt[3]
if resp[3] == 0x80:
raise MQTTException(resp[3])
return
# Wait for a single incoming MQTT message and process it.
# Subscribed messages are delivered to a callback previousl
# set by .set_callback() method. Other (internal) MQTT
# messages processed internally.
def wait_msg(self):
res = self.sock.read(1)
self.sock.setblocking(True)
if res is None:
return None
if res == b"":
raise OSError(-1)
if res == b"\xd0": # PINGRESP
sz = self.sock.read(1)[0]
assert sz == 0
return None
op = res[0]
if op & 0xf0 != 0x30:
return op
sz = self._recv_len()
topic_len = self.sock.read(2)
topic_len = (topic_len[0] << 8) | topic_len[1]
topic = self.sock.read(topic_len)
sz -= topic_len + 2
if op & 6:
pid = self.sock.read(2)
pid = pid[0] << 8 | pid[1]
sz -= 2
msg = self.sock.read(sz)
self.cb(topic, msg)
if op & 6 == 2:
pkt = bytearray(b"\x40\x02\0\0")
struct.pack_into("!H", pkt, 2, pid)
self.sock.write(pkt)
elif op & 6 == 4:
assert 0
# Checks whether a pending message from server is available.
# If not, returns immediately with None. Otherwise, does
# the same processing as wait_msg.
def check_msg(self):
self.sock.setblocking(False)
return self.wait_msg()

114
pg26/pnd.py Normal file
View File

@@ -0,0 +1,114 @@
import pndSRC as mypnd
import pndConfig as cfg
import ntptime
import ujson
import time
import machine
import array
import gc
gc.enable()
from machine import Pin, I2C, ADC
gc.enable()
class rt():
def run(self):
self.cycle = 1
while True:
try:
## main loop
gc.collect()
machine.idle()
self.mq = mqService()
self.mq.logConf(self.Psystem)
if hasattr(cfg.tasks, "gc_sensors"):
print("trying to log sensors")
time.sleep(5)
self.mq.logSensors(self.Sensors)
self.mq.close()
del self.mq
print(self.Psystem.status())
year, mon, day, h, m, s, nope, nope2 = time.localtime()
if((m % 55) == 0):
self.wifi.reconnect()
self.cycle = self.cycle + 1
if(self.cycle > 10000): self.cycle = 1
machine.idle()
time.sleep(self.looping)
except OSError as e:
mypnd.ecx.handle(self,e)
def backgroundTask(self):
lhttp = mypnd.webserver()
print('starting Webserver...')
## method with main loop goes here
lhttp.run()
def init(self, lastTry):
try:
self.bt = mypnd.bt()
self.wifi = mypnd.wifi()
self.wifi.disableAP()
self.Psystem = mypnd.system()
self.lastTry = 0
self.cycle = 0
self.looping = 0
self.Psystem.setCallback(self)
i = 0
self.lastTry = lastTry
self.wifi.connect()
ntptime.host = cfg.defaults.gc_ntp_host
try:
ntptime.settime()
except:
pass
if hasattr(cfg.tasks, "gc_sensors"):
self.Sensors = {}
for sens in cfg.tasks.gc_sensors:
if cfg.tasks.gc_sensors[sens]['ADC']:
self.Sensors[i] = mypnd.adcsens(cfg.tasks.gc_sensors[sens]['name'],cfg.tasks.gc_sensors[sens]['pin'])
else:
self.Sensors[i] = mypnd.sens(cfg.tasks.gc_sensors[sens]['name'],cfg.tasks.gc_sensors[sens]['type'],cfg.tasks.gc_sensors[sens]['pin'])
i += 1
self.looping = cfg.defaults.gc_looping
except OSError as e:
mypnd.ecx.handle(self,e)
class mqService():
def __init__(self):
try:
self.mqtt = mypnd.mqtt()
self.mqclient = self.mqtt.connect()
except OSError as e:
self.lastTry = 1
mypnd.ecx.handle(mypnd.ecx(),self,e)
def logConf(self, psys):
topic = cfg.mqtt.gc_topic_config
sys = psys
status = sys.statusJSON()
self.mqtt.publish(self.mqclient, topic, status)
def logSensors(self, sensors):
year, mon, day, h, m, s, nope, nope2 = time.localtime()
date = str(year) + "-" + str(mon) + "-" + str(day) + "T" + str(h) + ":" + str(m) + ":" + str(s)
for sens in sensors:
if sensors[sens].ADC:
jsens = ujson.dumps({ "name" : cfg.gc_name, "Time": date, "senso_name": sensors[sens].id, "value": sensors[sens].update()})
self.mqtt.publish(self.mqclient, cfg.mqtt.gc_topic_sensor, jsens)
else:
temp, hum = sensors[sens].update()
jsens = ujson.dumps({ "name" : cfg.gc_name, "Time": date, "senso_name": "Temperature_" + sensors[sens].id[-1], "value": temp})
self.mqtt.publish(self.mqclient, cfg.mqtt.gc_topic_sensor, jsens)
jsens = ujson.dumps({ "name" : cfg.gc_name, "Time": date, "senso_name": "Humidity_" + sensors[sens].id[-1], "value": hum})
self.mqtt.publish(self.mqclient, cfg.mqtt.gc_topic_sensor, jsens)
def close(self):
self.mqtt.disconnect(self.mqclient)
del self.mqclient
del self.mqtt

30
pg26/pndConfig.py Normal file
View File

@@ -0,0 +1,30 @@
gc_name = "pndESP_999_rc0.1"
class tasks:
gc_tasks = "Sensor;MQTT;WebServer"
gc_sensors = {0:{"name":"DHT11_1", "type":"DHT11","pin": 26, "ADC": False},
1:{"name":"Moisture_1", "type":"MOIST","pin": 32, "ADC": True},
2:{"name":"Moisture_2", "type":"MOIST","pin": 33, "ADC": True},
3:{"name":"Moisture_3", "type":"MOIST","pin": 35, "ADC": True}
}
class defaults:
gc_adc_min = 1024
gc_adc_max = 4096
gc_ntp_host = "ntp.org"
gc_looping = 60
gc_websrvport = 80
class wifi:
gc_ssid = "pnd_iot"
gc_secret = "this is not real: this is a Dream... Wake Up ;-D"
gc_ap = {}
class mqtt:
gc_host = "192.42.42.44" # needs to be changed
gc_port = 1883
gc_topic_config =f"pndiot/{gc_name}/config"
gc_topic_sensor =f"pndiot/{gc_name}/sensors"
gc_user = "pndiot"
gc_secret = "pndiot"