add initial version

This commit is contained in:
daneos 2023-02-09 13:00:59 +01:00
parent 696e91968b
commit 6453e9da5c
3 changed files with 527 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__/*

3
ArduinoWeatherStation Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env python3
from arduinows import start
start()

523
arduinows.py Normal file
View File

@ -0,0 +1,523 @@
import requests
from threading import Thread
from time import time, sleep
from datetime import datetime
# from itertools import groupby
from tango import AttrWriteType, DevState, DispLevel, DeviceProxy
from tango.server import run, Device, attribute, device_property
class ArduinoWeatherStation(Device):
address = device_property(
dtype=str,
doc="IP address",
)
port = device_property(
dtype=int,
default_value=5209,
doc="Port",
)
polling_time = device_property(
dtype=int,
default_value=2,
doc="Polling time",
)
timeout = device_property(
dtype=int,
default_value=5,
doc="Data request timeout",
)
stale_time = device_property(
dtype=int,
default_value=60,
doc="Stale time",
)
# buffer_size = device_property(
# dtype=int,
# default_value=30,
# doc="Data buffer size",
# )
fw_version = attribute(
label="FW version",
dtype=str,
access=AttrWriteType.READ,
display_level=DispLevel.EXPERT,
fget="get_fw_version"
)
eeprom_slots = attribute(
label="EEPROM slots",
dtype=int,
access=AttrWriteType.READ,
display_level=DispLevel.EXPERT,
fget="get_eeprom_slots"
)
eeprom_writes = attribute(
label="EEPROM write count",
dtype=int,
access=AttrWriteType.READ,
display_level=DispLevel.EXPERT,
fget="get_eeprom_writes"
)
sht30_status = attribute(
label="SHT30 status",
dtype=int,
access=AttrWriteType.READ,
display_level=DispLevel.EXPERT,
fget="get_sht30_status"
)
t_outA = attribute(
label="Outside temperature A",
dtype=float, unit="C",
access=AttrWriteType.READ,
fget="get_outA_temp"
)
t_outB = attribute(
label="Outside temperature B",
dtype=float, unit="C",
access=AttrWriteType.READ,
fget="get_outB_temp"
)
t_out_avg = attribute(
label="Average outside temperature",
dtype=float, unit="C",
access=AttrWriteType.READ,
fget="get_out_avg_temp"
)
t_box = attribute(
label="Box temperature",
dtype=float, unit="C",
access=AttrWriteType.READ,
fget="get_box_temp"
)
t_chip = attribute(
label="Chip temperature",
dtype=float, unit="C",
access=AttrWriteType.READ,
fget="get_chip_temp"
)
rh = attribute(
label="Relative humidity",
dtype=float, unit="%RH",
access=AttrWriteType.READ,
fget="get_rh"
)
ah = attribute(
label="Absolute humidity",
dtype=float, unit="g/m3",
access=AttrWriteType.READ,
fget="get_ah"
)
dew = attribute(
label="Dew point",
dtype=float, unit="C",
access=AttrWriteType.READ,
fget="get_dew"
)
bat1ADC = attribute(
label="Battery1 ADC",
dtype=int,
access=AttrWriteType.READ,
display_level=DispLevel.EXPERT,
fget="get_bat1ADC"
)
bat2ADC = attribute(
label="Battery2 ADC",
dtype=int,
access=AttrWriteType.READ,
display_level=DispLevel.EXPERT,
fget="get_bat2ADC"
)
pv1ADC = attribute(
label="PV1 ADC",
dtype=int,
access=AttrWriteType.READ,
display_level=DispLevel.EXPERT,
fget="get_pv1ADC"
)
pv2ADC = attribute(
label="PV2 ADC",
dtype=int,
access=AttrWriteType.READ,
display_level=DispLevel.EXPERT,
fget="get_pv2ADC"
)
bat1V = attribute(
label="Battery1 Voltage",
dtype=float, unit="V",
access=AttrWriteType.READ,
fget="get_bat1V"
)
bat2V = attribute(
label="Battery2 Voltage",
dtype=float, unit="V",
access=AttrWriteType.READ,
fget="get_bat2V"
)
pv1V = attribute(
label="PV1 Voltage",
dtype=float, unit="V",
access=AttrWriteType.READ,
fget="get_pv1V"
)
pv2V = attribute(
label="PV2 Voltage",
dtype=float, unit="V",
access=AttrWriteType.READ,
fget="get_pv2V"
)
rdADC = attribute(
label="Rain detector ADC",
dtype=int,
access=AttrWriteType.READ,
display_level=DispLevel.EXPERT,
fget="get_rdADC"
)
piezoADC = attribute(
label="Piezo sensor ADC",
dtype=int,
access=AttrWriteType.READ,
display_level=DispLevel.EXPERT,
fget="get_piezoADC"
)
rd = attribute(
label="Rain detector",
dtype=float, unit="%",
access=AttrWriteType.READ,
fget="get_rd"
)
piezo = attribute(
label="Piezo sensor",
dtype=float,
access=AttrWriteType.READ,
fget="get_piezo"
)
bat1Coef = attribute(
label="Bat1Coef",
dtype=float,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_bat1coef", fset="set_bat1coef"
)
bat2Coef = attribute(
label="Bat2Coef",
dtype=float,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_bat2coef", fset="set_bat2coef"
)
pv1Coef = attribute(
label="PV1Coef",
dtype=float,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_pv1coef", fset="set_pv1coef"
)
pv2Coef = attribute(
label="PV2Coef",
dtype=float,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_pv2coef", fset="set_pv2coef"
)
rdCoef = attribute(
label="RDCoef",
dtype=float,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_rdcoef", fset="set_rdcoef"
)
piezoCoef = attribute(
label="PiezoCoef",
dtype=float,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_piezocoef", fset="set_piezocoef"
)
bat1Off = attribute(
label="Bat1Off",
dtype=int,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_bat1off", fset="set_bat1off"
)
bat2Off = attribute(
label="Bat2Off",
dtype=int,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_bat2off", fset="set_bat2off"
)
pv1Off = attribute(
label="PV1Off",
dtype=int,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_pv1off", fset="set_pv1off"
)
pv2Off = attribute(
label="PV2Off",
dtype=int,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_pv2off", fset="set_pv2off"
)
rdOff = attribute(
label="rdOff",
dtype=int,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_rdoff", fset="set_rdoff"
)
piezoOff = attribute(
label="PiezoOff",
dtype=int,
access=AttrWriteType.READ_WRITE,
display_level=DispLevel.EXPERT,
fget="get_piezooff", fset="set_piezooff"
)
def init_device(self):
Device.init_device(self)
self.set_state(DevState.INIT)
self.url = "http://%s:%d/" % (self.address, self.port)
self.data = {}
self.comm_thread = CommunicationThread(self)
self.comm_thread.start()
self.set_state(DevState.ON)
def delete_device(self):
self.comm_thread.stop()
def get_fw_version(self):
return self.data["status"]["fw_version"]
def get_eeprom_slots(self):
return self.data["status"]["eeprom_slots"]
def get_eeprom_writes(self):
return self.data["status"]["eeprom_writes"]
def get_sht30_status(self):
return self.data["status"]["sht30_status"]
def get_outA_temp(self):
return self.data["temperature"]["out_a"]
def get_outB_temp(self):
return self.data["temperature"]["out_b"]
def get_out_avg_temp(self):
return self.data["temperature"]["out_avg"]
def get_box_temp(self):
return self.data["temperature"]["box"]
def get_chip_temp(self):
return self.data["temperature"]["chip"]
def get_rh(self):
return self.data["humidity"]["rel"]
def get_ah(self):
return self.data["humidity"]["abs"]
def get_dew(self):
return self.data["humidity"]["dew"]
def get_bat1ADC(self):
return self.data["adc"]["bat1"]
def get_bat2ADC(self):
return self.data["adc"]["bat2"]
def get_pv1ADC(self):
return self.data["adc"]["pv1"]
def get_pv2ADC(self):
return self.data["adc"]["pv2"]
def get_bat1V(self):
return self.data["power"]["bat1"]
def get_bat2V(self):
return self.data["power"]["bat2"]
def get_pv1V(self):
return self.data["power"]["pv1"]
def get_pv2V(self):
return self.data["power"]["pv2"]
def get_rdADC(self):
return self.data["adc"]["rd"]
def get_piezoADC(self):
return self.data["adc"]["piezo"]
def get_rd(self):
return self.data["rain"]["rd"]
def get_piezo(self):
return self.data["rain"]["piezo"]
def get_bat1coef(self):
return self.data["config"]["bat1_coef"]
def set_bat1coef(self, v):
self.comm_thread.write({"bat1_coef": v})
def get_bat2coef(self):
return self.data["config"]["bat2_coef"]
def set_bat2coef(self, v):
self.comm_thread.write({"bat2_coef": v})
def get_pv1coef(self):
return self.data["config"]["pv1_coef"]
def set_pv1coef(self, v):
self.comm_thread.write({"pv1_coef": v})
def get_pv2coef(self):
return self.data["config"]["pv2_coef"]
def set_pv2coef(self, v):
self.comm_thread.write({"pv2_coef": v})
def get_bat1off(self):
return self.data["config"]["bat1_off"]
def set_bat1off(self, v):
self.comm_thread.write({"bat1_off": v})
def get_bat2off(self):
return self.data["config"]["bat2_off"]
def set_bat2off(self, v):
self.comm_thread.write({"bat2_off": v})
def get_pv1off(self):
return self.data["config"]["pv1_off"]
def set_pv1off(self, v):
self.comm_thread.write({"pv1_off": v})
def get_pv2off(self):
return self.data["config"]["pv2_off"]
def set_pv2off(self, v):
self.comm_thread.write({"pv2_off": v})
def get_rdcoef(self):
return self.data["config"]["rd_coef"]
def set_rdcoef(self, v):
self.comm_thread.write({"rd_coef": v})
def get_piezocoef(self):
return self.data["config"]["piezo_coef"]
def set_piezocoef(self, v):
self.comm_thread.write({"piezo_coef": v})
def get_rdoff(self):
return self.data["config"]["rd_off"]
def set_rdoff(self, v):
self.comm_thread.write({"rd_off": v})
def get_piezooff(self):
return self.data["config"]["piezo_off"]
def set_piezooff(self, v):
self.comm_thread.write({"piezo_off": v})
class CommunicationThread(Thread):
def __init__(self, dev):
Thread.__init__(self)
self.dev = dev
self.quit = False
self.write_buffer = None
self.last_read = None
self.data_buffer = []
def run(self):
while not self.quit:
if self.write_buffer is not None:
self._write()
self._read()
self._check_stale_data()
sleep(self.dev.polling_time)
def _read(self):
try:
r = requests.get(self.dev.url, timeout=self.dev.timeout)
self.dev.data = r.json()
except Exception as e:
print("Read generated exception: %s" % str(e))
else:
self.last_read = time()
# self.data_buffer.append(data)
# if len(self.data_buffer) > self.dev.buffer_size:
# self.data_buffer.pop(0)
def _write(self):
requests.post(self.dev.url, json=self.write_buffer)
self.write_buffer = None
def _check_stale_data(self):
print("checking for stale data")
if self.last_read is not None:
if time() - self.last_read >= self.dev.stale_time:
print("all data stale, resetting")
DeviceProxy(self.dev.get_name()).Init()
self.dev.set_status("Device reset at %s due to stale data." % datetime.now().strftime("%Y-%m-%d/%H:%M:%S.%f/%Z"))
else:
print("not stale")
else:
print("no read yet")
# stale = []
# if len(self.data_buffer) >= self.dev.buffer_size:
# for k, v in self.data_buffer[0].items():
# if k in ("status", "config"):
# continue
# print("processing section %s" % k)
# for kk, vv in v.items():
# print("processing value %s" % kk)
# data = [s[k][kk] for s in self.data_buffer]
# print(data)
# r = self.all_equal(data)
# print("is stale? %s" % str(r))
# stale.append(r)
# if all(stale):
# def all_equal(self, iterable):
# g = groupby(iterable)
# return next(g, True) and not next(g, False)
def write(self, data):
self.write_buffer = data
def stop(self):
self.quit = True
def start():
run((ArduinoWeatherStation,))
if __name__ == "__main__":
start()