From 2038f9c88c8c6746960f693e70547ce6339ee145 Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Sun, 10 Mar 2024 12:40:26 +0100 Subject: [PATCH] Add ext scripts as example --- ext/stab.py | 67 +++++++++++++++++++ ext/stab_display.py | 152 ++++++++++++++++++++++++++++++++++++++++++++ ext/stab_reader.py | 138 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 357 insertions(+) create mode 100644 ext/stab.py create mode 100644 ext/stab_display.py create mode 100644 ext/stab_reader.py diff --git a/ext/stab.py b/ext/stab.py new file mode 100644 index 0000000..9950cc1 --- /dev/null +++ b/ext/stab.py @@ -0,0 +1,67 @@ +# import serial +# import io +# import time +# import os +import time + +from stab_reader import StabReader +from stab_display import StabDisplay + +I2C_ADDRESS_O = 0x3C # 011110+SA0+RW - 0x3C or 0x3D +I2C_ADDRESS_U = 0x3D # 011110+SA0+RW - 0x3C or 0x3D + +if __name__ == '__main__': + + # create objects + sr1 = StabReader(port='/dev/ttyUSB0') + sr2 = StabReader(port='/dev/ttyUSB1') + sao = StabDisplay(i2c_address=I2C_ADDRESS_O) + sau = StabDisplay(i2c_address=I2C_ADDRESS_U) + + # wait until at least one stab is online + while True: + sr1.read_state() + sr2.read_state() + if sr1.is_online() or sr2.is_online(): + break + + # check which stab device is the upper and which the lower + # SN oben: 1234567890123456 + # SN unten: 2345678901234567 + print('sr1 SN: ' + sr1.get_value('Seriennummer')) + print('sr2 SN: ' + sr2.get_value('Seriennummer')) + if sr1.get_value('Seriennummer') == '1234567890123456' or sr2.get_value('Seriennummer') == '2345678901234567': + sro = sr1 + sru = sr2 + else: + sro = sr2 + sru = sr1 + + # main loop + count = 4 + while True: + if count >= 4: + # read devices every 2 seconds + sro.read_state() + sru.read_state() + count = 0 + + # update displays every 500 ms + sao.set_values(v=sro.get_value('Solarspannung'), c=sro.get_value('Solarstrom'), + w=sro.get_value('Solarleistung'), d=sro.get_value('SolarenergieHeute'), + s=sro.get_value('SolarenergieGesammt'), wt=sro.get_value('Wassertemp'), + gt=sro.get_value('GeraeteTemp')) + # sao.set_values(v=sro.get_dummy('Solarspannung'), c=sro.get_dummy('Solarstrom'), + # w=sro.get_dummy('Solarleistung'), d=sro.get_dummy('SolarenergieHeute'), + # s=sro.get_dummy('SolarenergieGesammt'), wt=sro.get_dummy('Wassertemp'), + # gt=sro.get_dummy('GeraeteTemp')) + # sao.set_values(v='260.8', c='10.3276', w='2000.00', d='10000', s='999999', wt='33', gt='66') + sao.update() + sau.set_values(v=sru.get_value('Solarspannung'), c=sro.get_value('Solarstrom'), + w=sru.get_value('Solarleistung'), d=sru.get_value('SolarenergieHeute'), + s=sru.get_value('SolarenergieGesammt'), wt=sru.get_value('Wassertemp'), + gt=sru.get_value('GeraeteTemp')) + sau.update() + + time.sleep(0.5) # wait 500 ms + count = count + 1 diff --git a/ext/stab_display.py b/ext/stab_display.py new file mode 100644 index 0000000..b4d5cf4 --- /dev/null +++ b/ext/stab_display.py @@ -0,0 +1,152 @@ +# import math +# import time + +# import Adafruit_GPIO.SPI as SPI +import Adafruit_SSD1306 + +from PIL import Image +from PIL import ImageFont +from PIL import ImageDraw + + +# Raspberry Pi pin configuration: +RST = 24 +I2C_ADDRESS = 0x3C # 011110+SA0+RW - 0x3C or 0x3D + + +class StabDisplay: + + def __init__(self, i2c_address=I2C_ADDRESS): + + print('__init__(self, ' + str(i2c_address)) + + self.i2c_address = i2c_address + + self.disp = None + self.width = None + self.height = None + self.image = None + self.draw = None + + self.init_hw() + self.volt = '' + self.cur = '' + self.watt = '' + self.daily = '' + self.sum = '' + self.wtemp = '' + self.gtemp = '' + self.state = 0 + + # Load default font. + # self.font = ImageFont.load_default() + # Load font + self.font_s = ImageFont.truetype('Paul-le1V.ttf', 13) + self.font_vs = ImageFont.truetype('Paul-le1V.ttf', 10) + # self.font_b = ImageFont.truetype('bigshot.ttf', 20) + self.font_b = ImageFont.truetype('gotham-black.ttf', 19) + # Alternatively load a TTF font. Make sure the .ttf font file is in the same directory as this python script! + # Some nice fonts to try: http://www.dafont.com/bitmap.php + # font = ImageFont.truetype('Minecraftia.ttf', 8) + + def init_hw(self): + + try: + # 128x64 display with hardware I2C: + self.disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST, i2c_address=self.i2c_address) + + # Initialize library. + self.disp.begin() + + # Get display width and height. + self.width = self.disp.width + self.height = self.disp.height + + # Clear display. + self.disp.clear() + self.disp.display() + + # Create image buffer. + # Make sure to create image with mode '1' for 1-bit color. + self.image = Image.new('1', (self.width, self.height)) + + # Create drawing object. + self.draw = ImageDraw.Draw(self.image) + + except Exception as e: + self.online = False + else: + self.online = True + + def set_values(self, v, c, w, d, s, wt, gt): + + # print('StabDisplay::set_values(' + v + ', ' + c + ', ' + w + ', ' + d + ', ' + s + ', ' + wt + ', ' + gt + ' )') + self.volt = v + self.cur = c + self.watt = w + self.daily = d + self.sum = s + self.wtemp = wt + self.gtemp = gt + + def update(self): + + # print('StabDisplay::update()', self.volt, self.cur, self.watt, self.daily, self.sum, self.wtemp, self.gtemp) + + if self.online: + + # Clear image buffer by drawing a black filled box. + self.draw.rectangle((0, 0, self.width, self.height), outline=0, fill=0) + + # ################################# + # # 'aktuelle Leistung' # + # # \ 'Spannung' 'Strom' # + # # 'Gesammt kWh' 'Tag Wh' # + # # 'Wassertemp' 'GeraeteTemp' # + # ################################# + + char_left, char_top, char_right, char_bottom = self.font_b.getbbox(self.watt + ' W') + self.draw.text((self.width - char_right - 1, 1), self.watt + ' W', font=self.font_b, fill=255) + + rest = char_bottom + progress_list = ['|', '/', '-', '\\'] + self.draw.text((5, rest + 10), progress_list[self.state], font=self.font_s, fill=255) + self.state = self.state + 1 + if self.state > 3: + self.state = 0 + + char_left, char_top, char_right, char_bottom = self.font_s.getbbox(self.volt + ' V') + self.draw.text((self.width / 2 - char_right - 7, rest + 5), self.volt + ' V', font=self.font_s, fill=255) + + char_left, char_top, char_right, char_bottom = self.font_s.getbbox(self.cur + ' A') + self.draw.text((self.width - char_right - 7, rest + 5), self.cur + ' A', font=self.font_s, fill=255) + + rest = rest + char_bottom + lsum = len(self.sum) + ssum = self.sum[:lsum-3] + + char_left, char_top, char_right, char_bottom = self.font_s.getbbox(ssum + ' kWh') + self.draw.text((self.width / 2 - char_right - 7, rest + 10), ssum + ' kWh', font=self.font_s, fill=255) + + char_left, char_top, char_right, char_bottom = self.font_s.getbbox(self.daily + ' Wh') + self.draw.text((self.width - char_right - 7, rest + 10), self.daily + ' Wh', font=self.font_s, fill=255) + + rest = rest + char_bottom + lwt = len(self.wtemp) + char_left, char_top, char_right, char_bottom = self.font_vs.getbbox('W: ' + self.wtemp[:lwt-1] + ' °C') + self.draw.text((self.width / 2 - char_right - 7, rest + 15), 'W: ' + self.wtemp[:lwt-1] + ' °C', font=self.font_vs, fill=255) + + char_left, char_top, char_right, char_bottom = self.font_vs.getbbox('G: ' + self.gtemp + ' °C') + self.draw.text((self.width - char_right - 7, rest + 15), 'G: ' + self.gtemp + ' °C', font=self.font_vs, fill=255) + + self.disp.image(self.image) + self.disp.display() + + else: + self.init_hw() + if self.online: + self.update() + + + + diff --git a/ext/stab_reader.py b/ext/stab_reader.py new file mode 100644 index 0000000..79be641 --- /dev/null +++ b/ext/stab_reader.py @@ -0,0 +1,138 @@ +import serial + + +class StabReader: + + def __init__(self, port='/dev/ttyUSB0', baudrate=9600, timeout=1, + xonxoff=False, rtscts=False, dsrdtr=True): + self.port = port + self.baudrate = baudrate + self.timeout = timeout + self.xonxoff = xonxoff + self.rtscts = rtscts + self.dsrdtr = dsrdtr + self.statusDict = { + 'dummy0': '', + 'firmware': '', + 'Betriebstag': '', + 'Status': '', + 'DcTrenner': '', + 'DcRelais': '', + 'AcRelais': '', + 'Wassertemp': '', + 'WassertempMin': '', + 'WassertempMax': '', + 'SolltempSolar': '', + 'SolltempNetz': '', + 'GeraeteTemp': '', + 'IsoMessung': '', + 'Solarspannung': '', + 'dummy5.1': '', + 'Solarstrom': '', + 'Solarleistung': '', + 'SolarenergieHeute': '', + 'SolarenergieGesammt': '', + 'Netzernergie': '', + 'dummy6': '', + 'dummy7': '', + 'dummy8': '', + 'dummy9': '', + 'dummy10': '', + 'dummy11': '', + 'dummy12': '', + 'Seriennummer': '', + 'dummy13': '' + } + self.online = False + self.offline = 0 + + def get_value(self, name): + return self.statusDict[name] + + def is_online(self): + return self.online + + def read_state(self): + try: + # configure the serial connections (the parameters differs on the device you are connecting to) + with serial.Serial(port=self.port, baudrate=self.baudrate, timeout=self.timeout, + xonxoff=self.xonxoff, rtscts=self.rtscts, dsrdtr=self.dsrdtr) as ser: + ser.write(bytes('rs\r\n', encoding='utf8')) + + for line in ser: + #print(line) + if len(line) < 10: + # line = b'dr\tV1.31\t5\t12\t1\t1\t0\t660\t550\t725\t748\t500\t33\t89\t154.3\t154.83\t0.3276\t50.72\t7843\t34577\t0\t-13\t2.5\t519\t890\t869\t210\t1\t1234567890123456\t748\t1\r\n' + # line = b'dr\tV1.31\t6\t5\t0\t0\t0\t650\t550\t725\t748\t500\t32\t89\t130.5\t42.55\t0.0000\t0.00\t0\t34588\t0\t-3\t0.0\t679\t938\t917\t210\t1\t1234567890123456\t748\t111\r\n' + # line = b'dr\tV1.31\t5\t12\t1\t1\t0\t650\t550\t725\t748\t500\t33\t89\t134.2\t134.70\t0.0050\t0.67\t7854\t34588\t0\t1\t0.1\t269\t926\t905\t210\t1\t1234567890123456\t748\t80\r\n' + # print(line) + self.offline = self.offline + 1 + else: + self.offline = 0 + self.online = True + string = line.decode('utf-8') + strlist = list(string.split('\t')) + # print(strlist) + index = 0 + for d in self.statusDict: + self.statusDict[d] = strlist[index] + index = index + 1 + + if self.offline == 150: + self.online = False + self.statusDict['Solarspannung'] = '0' + self.statusDict['Solarstrom'] = '0' + self.statusDict['Solarleistung'] = '0' + + + except Exception as e: + print('Exception: ' + str(e)) + pass + finally: + # ser.close() + None + pass + + def get_dummy(self, name): + dummyDict = { + 'dummy0': '', + 'firmware': '', + 'Betriebstag': '', + 'Status': '', + 'DcTrenner': '', + 'DcRelais': '', + 'AcRelais': '', + 'Wassertemp': '', + 'WassertempMin': '', + 'WassertempMax': '', + 'SolltempSolar': '', + 'SolltempNetz': '', + 'GeraeteTemp': '', + 'IsoMessung': '', + 'Solarspannung': '', + 'dummy5.1': '', + 'Solarstrom': '', + 'Solarleistung': '', + 'SolarenergieHeute': '', + 'SolarenergieGesammt': '', + 'Netzernergie': '', + 'dummy6': '', + 'dummy7': '', + 'dummy8': '', + 'dummy9': '', + 'dummy10': '', + 'dummy11': '', + 'dummy12': '', + 'Seriennummer': '', + 'dummy13': '' + } + line = b'dr\tV1.31\t5\t12\t1\t1\t0\t660\t550\t725\t748\t500\t33\t89\t154.3\t154.83\t0.3276\t50.72\t7843\t34577\t0\t-13\t2.5\t519\t890\t869\t210\t1\t1234567890123456\t748\t1\r\n' + # line = b'dr\tV1.31\t6\t5\t0\t0\t0\t650\t550\t725\t748\t500\t32\t89\t130.5\t42.55\t0.0000\t0.00\t0\t34588\t0\t-3\t0.0\t679\t938\t917\t210\t1\t1234567890123456\t748\t111\r\n' + # line = b'dr\tV1.31\t5\t12\t1\t1\t0\t650\t550\t725\t748\t500\t33\t89\t134.2\t134.70\t0.0050\t0.67\t7854\t34588\t0\t1\t0.1\t269\t926\t905\t210\t1\t1234567890123456\t748\t80\r\n' + string = line.decode('utf-8') + strlist = list(string.split('\t')) + index = 0 + for d in dummyDict: + dummyDict[d] = strlist[index] + index = index + 1 + return dummyDict[name]