diff --git a/RPi5/boot/firmware/config.txt b/RPi5/boot/firmware/config.txt new file mode 100644 index 000000000..e848c0c59 --- /dev/null +++ b/RPi5/boot/firmware/config.txt @@ -0,0 +1,61 @@ +# For more options and information see +# http://rptl.io/configtxt +# Some settings may impact device functionality. See link above for details + +# Uncomment some or all of these to enable the optional hardware interfaces +#dtparam=i2c_arm=on +#dtparam=i2s=on +#dtparam=spi=on +dtparam=uart0 + +# --------------------- pi-ager settings --------- +# Use Pi-Ager Pins 11/13 GPIO 17/27 for I2C +dtoverlay=i2c-gpio,bus=3,i2c_gpio_sda=17,i2c_gpio_scl=27 +# Use Pi-Ager Pin 16 for MCP3204 +dtoverlay=spi1-1cs,cs0_pin=16 +# ----------------------------------------------- + +# Enable audio (loads snd_bcm2835) +dtparam=audio=on + +# Additional overlays and parameters are documented +# /boot/firmware/overlays/README + +# Automatically load overlays for detected cameras +camera_auto_detect=1 + +# Automatically load overlays for detected DSI displays +display_auto_detect=1 + +# Automatically load initramfs files, if found +auto_initramfs=1 + +# Enable DRM VC4 V3D driver +dtoverlay=vc4-kms-v3d +max_framebuffers=2 + +# Don't have the firmware create an initial video= setting in cmdline.txt. +# Use the kernel's default instead. +disable_fw_kms_setup=1 + +# Disable compensation for displays with overscan +disable_overscan=1 + +# Run as fast as firmware / board allows +arm_boost=1 + +[cm4] +# Enable host mode on the 2711 built-in XHCI USB controller. +# This line should be removed if the legacy DWC2 controller is required +# (e.g. for USB device mode) or if USB support is not required. +otg_mode=1 + +[all] + +enable_uart=1 +# ------------------------------ pi-ager settings ----------------- +dtoverlay=miniuart-bt +# force_turbo=1 +# ----------------------------------------------------------------- + + diff --git a/RPi5/boot/firmware/setup.txt b/RPi5/boot/firmware/setup.txt new file mode 100644 index 000000000..1d60dd535 --- /dev/null +++ b/RPi5/boot/firmware/setup.txt @@ -0,0 +1,68 @@ +# Initial Konfiguration +# Pi-Ager + +# Standard Hostname Pi-Ager +# Standard Passwoerter für alle raspberry +# +# Nur ausgefüllte Werte werden gesetzt +# Die Variablennamen dürfen nicht verändert werden! +# Wenn die Werte Sonderzeichen wie /?}][{|@!"§$%&-_.:,;#+~* oder Leerzeichen enthalten, +# müssen die Werte in 'Single Quotes' gesetzt werden. 'Single Quotes' dürfen dann nicht +# Bestandteil des Wertes sein! +# +# Z.B.: wlankey='FRITZ!Box 7490 |&;()<>"\$`^~@{}.' +# +# Logfile setup.log wird unter Linux im Verzeichnis /boot/firmware/ angelegt, +# und unter Windows mit der SD-Card in einem USB Lesegerät im Drive 'bootfs' im Verzeichnis /. +# + +# Hostname, wie soll der Raspberry Pi im Netzwerk heissen: +piname='pi-ager' + +# Passwort für Benutzer pi: +pipass='raspberry' + +# Passwort für Benutzer root: +rootpass='raspberry' + +# Passwort für Benutzer pi-ager auf der Webiste settings, admin, webcam: +webguipw='raspberry' + +# Passwort für Zugriff auf Datenbankverwaltung phpliteadmin: +dbpw='raspberry' + +#-------------------------------------------------------------------------------- +# Pi-Ager funktioniert auch ohne Router und ohne Internet Verbindung, +# denn im Pi-Ager steht simultan neben einer Verbindung mit einem Internet Router +# ein Accesspoint zur Verfügung. +# Der Accesspoint kann via Smartphone oder Tablet erreicht werden. +# Der Pi-Ager Accesspoint hat die WLAN SSID 'pi-ager' mit dem Default-Passwort '1234567890'. +# Der Pi-Ager ist dann über die IP Adresse 10.0.0.1 via SSH ereichbar. +# Der Pi-Ager Webserver kann mit einem Browser unter der URL http://10.0.0.1/ erreicht werden. +# Bei der erstmaligen Verbindung zum Accesspoint erscheint auch ein 'captive portal' mit +# Hinweisen zum Setup einer Verbindung zu einem WLAN Router. +# Auf der ADMIN Seite können dann Datum und Uhrzeit gesetzt werden +# und auch die Parameter für einen WLAN Router (SSID und Password). +# Das Default-Passwort für den Accesspoint kann auf der ADMIN-Seite geändert werden. +#------------------------------------------------------------------------------- + +# WLAN Netzwerkname: +wlanssid='your WLAN SSID' + +# WLAN Schlüssel (mindesten 8 Zeichen): +wlankey='your WLAN key' + +# ISO code your country, e.g. DE, GB: +country='DE' + +# Temperature/Humidity sensor attached to pi-ager: +# Supported types are : DHT11, DHT22, SHT75, SHT85, SHT3x, SHT3x-mod, AHT1x, AHT1x-mod, AHT2x, AHT30, SHT4x-A, SHT4x-B, SHT4x-C +sensor='SHT3x' + +# hmi display device name: +# valid device names: NX3224K028 or NX3224T028 or NX3224F028 +# z.B. : hmidisplay='NX3224K028' +hmidisplay= + +# setup.txt nach boot löschen? leer lassen für löschen oder 1 für behalten +keepconf=1 diff --git a/RPi5/lib/systemd/system/pi-ager_main.service b/RPi5/lib/systemd/system/pi-ager_main.service new file mode 100644 index 000000000..e6b51d950 --- /dev/null +++ b/RPi5/lib/systemd/system/pi-ager_main.service @@ -0,0 +1,17 @@ +[Unit] +Description=Start main routine of Pi-Ager +After=network-online.target +After=bluetooth.target +Wants=network-online.target + +[Service] +Type=simple +ExecStart=python3 /opt/pi-ager/main.py 1>/dev/null 2>&1 +ExecStartPre=ln -sf /dev/ttyAMA0 /dev/serial0 +PIDFile=/tmp/pi-ager_main.pid +StandardOutput=null +StandardError=null + +[Install] +Alias=pi-ager.service +WantedBy=multi-user.target \ No newline at end of file diff --git a/RPi5/lib/systemd/system/setup_pi-ager.service b/RPi5/lib/systemd/system/setup_pi-ager.service new file mode 100644 index 000000000..d47972b50 --- /dev/null +++ b/RPi5/lib/systemd/system/setup_pi-ager.service @@ -0,0 +1,15 @@ +[Unit] +Description=Automatsches Installationsscript für pi-ager zum Setzen von Passwörter und WIFI-Zugang, abhängig von setup.txt in /boot/firmware +# Before=rc-local.service lighttpd.service +Before=rc-local.service +After=NetworkManager.service + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/setup_pi-ager.sh +ExecStartPre=ln -sf /dev/ttyAMA0 /dev/serial0 +StandardOutput=append:/boot/firmware/setup.log +StandardError=append:/boot/firmware/setup.log + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/RPi5/opt/pi-ager/main/RPi/GPIO/__init__.py b/RPi5/opt/pi-ager/main/RPi/GPIO/__init__.py new file mode 100644 index 000000000..310ab276d --- /dev/null +++ b/RPi5/opt/pi-ager/main/RPi/GPIO/__init__.py @@ -0,0 +1,25 @@ +# Copyright (c) 2012-2021 Ben Croston +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""This package provides a Python module to control the GPIO on a Raspberry Pi""" + +from main.RPi._GPIO import * + +VERSION = '0.7.1a4' diff --git a/RPi5/opt/pi-ager/main/RPi/GPIO/__pycache__/__init__.cpython-311.pyc b/RPi5/opt/pi-ager/main/RPi/GPIO/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 000000000..d4b9e4e5a Binary files /dev/null and b/RPi5/opt/pi-ager/main/RPi/GPIO/__pycache__/__init__.cpython-311.pyc differ diff --git a/RPi5/opt/pi-ager/main/RPi/_GPIO.cpython-310-arm-linux-gnueabihf.so b/RPi5/opt/pi-ager/main/RPi/_GPIO.cpython-310-arm-linux-gnueabihf.so new file mode 100644 index 000000000..fc5a28a25 Binary files /dev/null and b/RPi5/opt/pi-ager/main/RPi/_GPIO.cpython-310-arm-linux-gnueabihf.so differ diff --git a/RPi5/opt/pi-ager/main/RPi/_GPIO.cpython-311-arm-linux-gnueabihf.so b/RPi5/opt/pi-ager/main/RPi/_GPIO.cpython-311-arm-linux-gnueabihf.so new file mode 100644 index 000000000..030fd4ba6 Binary files /dev/null and b/RPi5/opt/pi-ager/main/RPi/_GPIO.cpython-311-arm-linux-gnueabihf.so differ diff --git a/var/www/modules/names.json b/RPi5/opt/pi-ager/main/RPi/__init__.py similarity index 100% rename from var/www/modules/names.json rename to RPi5/opt/pi-ager/main/RPi/__init__.py diff --git a/RPi5/opt/pi-ager/main/RPi/__pycache__/__init__.cpython-311.pyc b/RPi5/opt/pi-ager/main/RPi/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 000000000..a104a30c6 Binary files /dev/null and b/RPi5/opt/pi-ager/main/RPi/__pycache__/__init__.cpython-311.pyc differ diff --git a/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_dht.py b/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_dht.py new file mode 100644 index 000000000..e51023cb4 --- /dev/null +++ b/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_dht.py @@ -0,0 +1,243 @@ +# -*- coding: utf-8 -*- + +"""This class is for handling the dht_adafruit sensor from sensirion.""" + +__author__ = "Claus Fischer" +__copyright__ = "Copyright 2019, The Pi-Ager Project" +__credits__ = ["Claus Fischer"] +__license__ = "GPL" +__version__ = "1.0.0" +__maintainer__ = "Claus Fischer" +__email__ = "DerBurgermeister@pi-ager.org" +__status__ = "Production" + +import os +# import inspect +from main.pi_ager_cl_logger import cl_fact_logger +import time + +import pi_ager_gpio_config + +from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type +from main.pi_ager_cx_exception import * +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +from sensors.pi_ager_cl_sensor import cl_sensor +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor +import lgpio as sbc + +class cl_sensor_dht(cl_sensor): + DHTAUTO=0 + DHT11=1 + DHTXX=2 + + DHT_GOOD=0 + DHT_BAD_CHECKSUM=1 + DHT_BAD_DATA=2 + DHT_TIMEOUT=3 + + def __init__(self): +# cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + + super().__init__(cl_fact_main_sensor_type.get_instance()) + # remove i2c_gpio kernel driver to release GPIO17 and GPIO27 pins + # so that rpi-lgpio can access these pins + # Using a RPi zero W is not recommended due to poor performance + os.system('rmmod i2c_gpio') + + # check Pi model + stream = os.popen('cat /proc/device-tree/model') + output = stream.read().rstrip('\n') + if ('Raspberry Pi 5' in output): + cl_fact_logger.get_instance().debug("Pi5 detected") + self._chip = sbc.gpiochip_open(4) # 4 is for Pi5 + else: + cl_fact_logger.get_instance().debug("Other Pis detected") + self._chip = sbc.gpiochip_open(0) # 0 is fo all other Pi devices + + self._gpio = pi_ager_gpio_config.gpio_sensor_data + self._model = self._sensor_dht + + self._new_data = False + + self._bits = 0 + self._code = 0 + self._last_edge_tick = 0 + + self._timestamp = time.time() + self._status = self.DHT_TIMEOUT + self._temperature = 0.0 + self._humidity = 0.0 + + sbc.gpio_set_watchdog_micros(self._chip, self._gpio, 1000) # watchdog after 1 ms + self._cb = sbc.callback(self._chip, self._gpio, sbc.RISING_EDGE, self._rising_edge) + + + def _datum(self): + return ((self._timestamp, self._gpio, self._status, self._temperature, self._humidity)) + + def _validate_DHT11(self, b1, b2, b3, b4): + t = b2 + h = b4 + if (b1 == 0) and (b3 == 0) and (t <= 60) and (h >= 9) and (h <= 90): + valid = True + else: + valid = False + return (valid, t, h) + + def _validate_DHTXX(self, b1, b2, b3, b4): + if b2 & 128: + div = -10.0 + else: + div = 10.0 + t = float(((b2&127)<<8) + b1) / div + h = float((b4<<8) + b3) / 10.0 + if (h <= 110.0) and (t >= -50.0) and (t <= 135.0): + valid = True + else: + valid = False + return (valid, t, h) + + def _decode_dhtxx(self): + """ + +-------+-------+ + | DHT11 | DHTXX | + +-------+-------+ + Temp C| 0-50 |-40-125| + +-------+-------+ + RH% | 20-80 | 0-100 | + +-------+-------+ + + 0 1 2 3 4 + +------+------+------+------+------+ + DHT11 |check-| 0 | temp | 0 | RH% | + |sum | | | | | + +------+------+------+------+------+ + DHT21 |check-| temp | temp | RH% | RH% | + DHT22 |sum | LSB | MSB | LSB | MSB | + DHT33 | | | | | | + DHT44 | | | | | | + +------+------+------+------+------+ + """ + b0 = self._code & 0xff + b1 = (self._code >> 8) & 0xff + b2 = (self._code >> 16) & 0xff + b3 = (self._code >> 24) & 0xff + b4 = (self._code >> 32) & 0xff + + chksum = (b1 + b2 + b3 + b4) & 0xFF + + if chksum == b0: + if self._model == self.DHT11: + valid, t, h = self._validate_DHT11(b1, b2, b3, b4) + elif self._model == self.DHTXX: + valid, t, h = self._validate_DHTXX(b1, b2, b3, b4) + else: # AUTO + # Try DHTXX first. + valid, t, h = self._validate_DHTXX(b1, b2, b3, b4) + if not valid: + # try DHT11. + valid, t, h = self._validate_DHT11(b1, b2, b3, b4) + if valid: + self._timestamp = time.time() + self._temperature = t + self._humidity = h + self._status = self.DHT_GOOD + else: + self._status = self.DHT_BAD_DATA + else: + self._status = self.DHT_BAD_CHECKSUM + self._new_data = True + + def _rising_edge(self, chip, gpio, level, tick): + if level != sbc.TIMEOUT: + edge_len = tick - self._last_edge_tick + self._last_edge_tick = tick + if edge_len > 2e8: # 0.2 seconds + self._bits = 0 + self._code = 0 + else: + self._code <<= 1 + if edge_len > 1e5: # 100 microseconds, so a high bit + self._code |= 1 + self._bits += 1 + else: # watchdog + if self._bits >= 30: + self._decode_dhtxx() + + def _trigger(self): + sbc.gpio_claim_output(self._chip, self._gpio, 0) + if self._model != self.DHTXX: + time.sleep(0.015) + else: + time.sleep(0.001) + self._bits = 0 + self._code = 0 + sbc.gpio_claim_alert(self._chip, self._gpio, sbc.RISING_EDGE) + + def cancel(self): + """ + """ + if self._cb is not None: + self._cb.cancel() + self._cb = None + + def read(self): + """ + """ + self._new_data = False + self._status = self.DHT_TIMEOUT + self._trigger() + for i in range(20): # timeout after 1 seconds. + time.sleep(0.05) + if self._new_data: + break + if not self._new_data: + cl_fact_logger.get_instance().debug("DHT11/DHT22 data timeout") + datum = self._datum() + return datum + + def get_current_data(self): +# cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + self._error_counter = 0 + self._max_errors = 5 + + while self._error_counter < self._max_errors: + try: + # Try to grab a sensor reading. Use the read_retry method which will retry up + # to times to get a sensor reading (waiting seconds between each retry). + cl_fact_logger.get_instance().debug("Try to read from Sensor DHT%s Pin %d" % (self._sensor_dht, self._gpio)) + data = self.read() + if (data[2] != self.DHT_GOOD): + self._error_counter += 1 + time.sleep(1) + continue + + current_humidity = data[4] + hum_offset = self.get_humidity_offset() + current_humidity += hum_offset + if (current_humidity > 100.0): + current_humidity = 100.0 + if (current_humidity < 0.0): + current_humidity = 0.0 + current_temperature = data[3] + + cl_fact_logger.get_instance().debug("Temperature in Celsius is : %.2f °C" %current_temperature) + cl_fact_logger.get_instance().debug("Relative Humidity is : %.2f %%RH" %current_humidity) + dewpoint = super().get_dewpoint(current_temperature, current_humidity) + + (temperature_dewpoint, humidity_absolute) = dewpoint + self.measured_data = (current_temperature, current_humidity, temperature_dewpoint, humidity_absolute) + return(self.measured_data) + + except Exception as cx_error: + self._error_counter = self._error_counter + 1 + if (self._error_counter == 1): + cl_fact_logger.get_instance().exception(cx_error) + else: + cl_fact_logger.get_instance().error(f"Retry getting measurement from DHT device. Current retry count : {self._error_counter}, max retry count : {self._max_errors}") + time.sleep(1) + + cl_fact_logger.get_instance().debug(_('Too many measurement errors occurred!')) + raise cx_measurement_error (_('Too many measurement errors occurred!')) + + diff --git a/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_dht11.py b/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_dht11.py new file mode 100644 index 000000000..6e12c3a26 --- /dev/null +++ b/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_dht11.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +"""This class is for handling the dht11 sensor from sensirion.""" + +__author__ = "Claus Fischer" +__copyright__ = "Copyright 2019, The Pi-Ager Project" +__credits__ = ["Claus Fischer"] +__license__ = "GPL" +__version__ = "1.0.0" +__maintainer__ = "Claus Fischer" +__email__ = "DerBurgermeister@pi-ager.org" +__status__ = "Production" + +from abc import ABC, abstractmethod +# import inspect +from main.pi_ager_cl_logger import cl_fact_logger +# import time + +import pi_ager_gpio_config + +# from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type +from main.pi_ager_cx_exception import * +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +# from sensors.pi_ager_cl_sensor import cl_sensor +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor +from sensors.pi_ager_cl_sensor_dht import cl_sensor_dht + +class cl_sensor_dht11(cl_sensor_dht): + DHTAUTO=0 + DHT11=1 + DHTXX=2 + + def __init__(self, i_sensor_type, i_active_sensor): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # if "get_instance" not in inspect.stack()[1][3]: + # raise cx_direct_call(self,"Please use factory class" ) + # self.o_sensor_type = i__sensor_type + self._sensor_dht = self.DHT11 + # super().__init__(self.o_sensor_type) + super().__init__() + + def get_current_data(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + self.measured_data = super().get_current_data() + return(self.measured_data) + + +class cl_fact_sensor_dht11(ABC): + # fact_main_sensor_type = cl_fact_main_sensor_type() + __o_instance = None + + @classmethod + def get_instance(self, i_sensor_type, i_active_sensor): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + if cl_fact_sensor_dht11.__o_instance is not None: + return(cl_fact_sensor_dht11.__o_instance) + cl_fact_sensor_dht11.__o_instance = cl_sensor_dht11(i_sensor_type, i_active_sensor) + return(cl_fact_sensor_dht11.__o_instance) + + @classmethod + def set_instance(self, i_instance): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + cl_fact_sensor_dht11.__o_instance = i_instance + + def __init__(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + pass + diff --git a/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_dht22.py b/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_dht22.py new file mode 100644 index 000000000..f5a38c699 --- /dev/null +++ b/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_dht22.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- + +"""This class is for handling the dht22 sensor from sensirion.""" + +__author__ = "Claus Fischer" +__copyright__ = "Copyright 2019, The Pi-Ager Project" +__credits__ = ["Claus Fischer"] +__license__ = "GPL" +__version__ = "1.0.0" +__maintainer__ = "Claus Fischer" +__email__ = "DerBurgermeister@pi-ager.org" +__status__ = "Production" + +from abc import ABC, abstractmethod +# import inspect +from main.pi_ager_cl_logger import cl_fact_logger +# import time + +# import pi_ager_gpio_config + +# from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type +from main.pi_ager_cx_exception import * +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +# from sensors.pi_ager_cl_sensor import cl_sensor +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor +from sensors.pi_ager_cl_sensor_dht import cl_sensor_dht + +class cl_sensor_dht22(cl_sensor_dht): + DHTAUTO=0 + DHT11=1 + DHTXX=2 + + def __init__(self, i_sensor_type, i_active_sensor): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # if "get_instance" not in inspect.stack()[1][3]: + # raise cx_direct_call(self,"Please use factory class" ) + # self.o_sensor_type = i_sensor_type + self._sensor_dht = self.DHTXX + # super().__init__(self.o_sensor_type) + super().__init__() + + def get_current_data(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + self.measured_data = super().get_current_data() + return(self.measured_data) + + +class cl_fact_sensor_dht22(ABC): + # fact_main_sensor_type = cl_fact_main_sensor_type() + __o_instance = None + + @classmethod + def get_instance(self, i_sensor_type, i_active_sensor): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + if cl_fact_sensor_dht22.__o_instance is not None: + return(cl_fact_sensor_dht22.__o_instance) + cl_fact_sensor_dht22.__o_instance = cl_sensor_dht22(i_sensor_type, i_active_sensor) + return(cl_fact_sensor_dht22.__o_instance) + + @classmethod + def set_instance(self, i_instance): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + cl_fact_sensor_dht22.__o_instance = i_instance + + + def __init__(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + pass + diff --git a/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_sht75.py b/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_sht75.py new file mode 100644 index 000000000..23ca2407f --- /dev/null +++ b/RPi5/opt/pi-ager/sensors/pi_ager_cl_sensor_sht75.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- + +"""This class is for handling the SHT75 sensor from sensirion.""" + +__author__ = "Claus Fischer" +__copyright__ = "Copyright 2019, The Pi-Ager Project" +__credits__ = ["Claus Fischer"] +__license__ = "GPL" +__version__ = "1.0.0" +__maintainer__ = "Claus Fischer" +__email__ = "DerBurgermeister@pi-ager.org" +__status__ = "Production" + +import os +import RPi.GPIO as gpio +from abc import ABC, abstractmethod +from main.pi_ager_cl_logger import cl_fact_logger +# import time +# import main.pi_sht1x as pi_sht1x +import pi_sht1x +import pi_ager_gpio_config + +# from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type +from main.pi_ager_cx_exception import * +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +from sensors.pi_ager_cl_sensor import cl_sensor +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor + +class cl_sensor_sht75(cl_sensor): + + def __init__(self, i_sensor_type, i_active_sensor): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # remove i2c_gpio kernel driver to release GPIO17 and GPIO27 pins + # so that RPi.GPIO can access these pins + os.system('rmmod i2c_gpio') + + self.o_sensor_type = i_sensor_type + self.o_active_sensor = i_active_sensor + + self._current_temperature = 0 + self._current_humidity = 0 + self._max_errors = 5 + + gpio.setup(pi_ager_gpio_config.gpio_sensor_data, gpio.IN) + gpio.setup(pi_ager_gpio_config.gpio_sensor_sync, gpio.OUT) + + self._sensor_sht = pi_sht1x.SHT1x(pi_ager_gpio_config.gpio_sensor_data, pi_ager_gpio_config.gpio_sensor_sync, gpio_mode=pi_ager_gpio_config.board_mode) + + def get_current_data(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + self._error_counter = 0 + + while self._error_counter < self._max_errors: + + try: + hum_offset = self.get_humidity_offset() + self._current_temperature = self._get_current_temperature() + humidity_s = self._get_current_humidity() + hum_offset + if (humidity_s > 100.0): + humidity_s = 100.0 + if (humidity_s < 0.0): + humidity_s = 0.0 + self._current_humidity = humidity_s + + self._dewpoint = super().get_dewpoint(self._current_temperature, self._current_humidity) + cl_fact_logger.get_instance().debug("sht75 temperature : %.2f °C" % self._current_temperature) + cl_fact_logger.get_instance().debug("sht75 humidity : %.2f %%RH" % self._current_humidity) + + (temperature_dewpoint, humidity_absolute) = self._dewpoint + + self.measured_data = (self._current_temperature, self._current_humidity, temperature_dewpoint, humidity_absolute) + return(self.measured_data) + + except Exception as cx_error: + self._error_counter = self._error_counter + 1 + if (self._error_counter == 1): + cl_fact_logger.get_instance().exception(cx_error) + else: + cl_fact_logger.get_instance().error(f"Retry getting measurement from SHT75. Current retry count : {self._error_counter}, max retry count : {self._max_errors}") + + cl_fact_logger.get_instance().debug('Too many measurement errors occurred!') + raise cx_measurement_error(_('Too many measurement errors occurred!')) + + def _get_current_temperature(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + + self._sensor_sht.read_temperature() + + Temperature_Celsius = self._sensor_sht.temperature_celsius + # Temperature_Fahrenheit = self._sensor_sht.temperature_celsius * 9/5 + 32 + + # cl_fact_logger.get_instance().debug("Temperature in Celsius is : %.2f °C" %Temperature_Celsius) + # cl_fact_logger.get_instance().debug("Temperature in Fahrenheit is : %.2f F" %Temperature_Fahrenheit) + + self._current_temperature = Temperature_Celsius + + return(self._current_temperature) + + def _get_current_humidity(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + + self._sensor_sht.read_humidity() + Humidity = self._sensor_sht.humidity + + # cl_fact_logger.get_instance().debug("Relative Humidity is : %.2f %%RH" %Humidity) + + self._current_humidity = Humidity + return(self._current_humidity) + + +class cl_fact_sensor_sht75(ABC): + __o_instance = None + + @classmethod + def get_instance(self, i_sensor_type, i_active_sensor): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + if cl_fact_sensor_sht75.__o_instance is not None: + return(cl_fact_sensor_sht75.__o_instance) + cl_fact_sensor_sht75.__o_instance = cl_sensor_sht75(i_sensor_type, i_active_sensor) + return(cl_fact_sensor_sht75.__o_instance) + + @classmethod + def set_instance(self, i_instance): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + cl_fact_sensor_sht75.__o_instance = i_instance + + + def __init__(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + pass + diff --git a/RPi5/usr/local/bin/modify_nmconnection b/RPi5/usr/local/bin/modify_nmconnection new file mode 100644 index 000000000..c8f4ffd5c --- /dev/null +++ b/RPi5/usr/local/bin/modify_nmconnection @@ -0,0 +1,45 @@ +#!/usr/bin/python3 +import sys + +def main(): + + if len(sys.argv) != 6: + print("Usage must equal [filename] [ssid] [psk] [uuid] [timestamp]") + sys.exit(1) + + filename = sys.argv[1] + ssid = sys.argv[2] + psk = sys.argv[3] + uuid = sys.argv[4] + timestamp = sys.argv[5] + # filename = "test.nmconnection" + # print("ssid : " + ssid) + # print("psk : " + psk) + # print("uuid : " + uuid) + # print("timestamp : " + timestamp) + + reading_file = open(filename, "r") + + new_file_content = "" + for line in reading_file: + stripped_line = line.strip() + + if ("ssid=" in stripped_line): + new_line = "ssid=" + ssid + elif ("psk=" in stripped_line): + new_line = "psk=" + psk + elif ("uuid=" in stripped_line): + new_line = "uuid=" + uuid + elif ("timestamp=" in stripped_line): + new_line = "timestamp=" + timestamp + else: + new_line = stripped_line + new_file_content += new_line +"\n" + reading_file.close() + + writing_file = open(filename, "w") + writing_file.write(new_file_content) + writing_file.close() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/RPi5/usr/local/bin/pi-ager_image.sh b/RPi5/usr/local/bin/pi-ager_image.sh new file mode 100644 index 000000000..ae5734a1c --- /dev/null +++ b/RPi5/usr/local/bin/pi-ager_image.sh @@ -0,0 +1,619 @@ +#!/bin/bash + +# Script-Name: pi-ager_image +# Version : 0.1.0 +# Autor : DerBurgermeister, überarbeitet von phylax +# Datum : 11.06.2021 +# Dieses Script erstellt aus einem Backup ein Image. Nur für internen Gebrauch +# Vorher auf dem Source System noch folgende Befehle ausführen: +# apt -y update && apt -y upgrade && apt -y install linux-image && apt --fix-broken install +# Grund: Bei einem Kernel Upgrade gibt es Probleme +##################################################################### +#Variablen +##################################################################### +# + +# Pfad zur NFS Freigabe (Muss im NAS angelegt werden) +NFSVOL=$(sqlite3 -cmd ".timeout 5000" /var/www/config/pi-ager.sqlite3 "select nfsvol from config_nfs_backup where active = 1") + +# dieses Verzeichniss muss im NAS angelegt sein +# SUBDIR=$(sqlite3 -cmd ".timeout 5000" /var/www/config/pi-ager.sqlite3 "select subdir from config_nfs_backup where active = 1") + +#NFSMOUNT=/home/pi/backup # Pfad auf dem Pi indem das Backup gespeichert wird +# NFSMOUNT=$(sqlite3 -cmd ".timeout 5000" /var/www/config/pi-ager.sqlite3 "select nfsmount from config_nfs_backup where active = 1") +NFSMOUNT="/home/nfs/public" + +# setzt sich zusammen aus dem Dateipfad auf dem Pi und dem Verzeichnis im NAS +# BACKUP_PFAD=$(sqlite3 -cmd ".timeout 5000" /var/www/config/pi-ager.sqlite3 "select backup_path from config_nfs_backup where active = 1") +BACKUP_PFAD="$NFSMOUNT" + +#z.B. NFSOPT="nosuid,nodev,rsize=65536,wsize=65536,intr,noatime" +NFSOPT=$(sqlite3 -cmd ".timeout 5000" /var/www/config/pi-ager.sqlite3 "select nfsopt from config_nfs_backup where active = 1") + +# Name des Backup +BACKUP_NAME=$(sqlite3 -cmd ".timeout 5000" /var/www/config/pi-ager.sqlite3 "select backup_name from config_nfs_backup where active = 1") + +# ENDE VARIABLEN + +##################################################################### +# Skript (hier sollten nur erfahrene User anpassungen machen!) +##################################################################### +COMMAND_LINE_OPTIONS_HELP=' +Command line options: + -f Source Filename or + -l Take the last Backup file + -c Make a Copy of the input File. Otherwise the input file will be changed + -m my Image - Do not delete all + -h Print this help menu + +Examples: + + Copy last backup file to a new image file + '`basename $0`' -c -l + + Copy backup file to a new image file + '`basename $0`' -c -f PiAgerBackup_2020-01-22-07:02:17.img + + Use backup file as a new image file - Backup is then the image + '`basename $0`' -f PiAgerBackup_2020-01-22-07:02:17.img + + Create and copy my Image - do not delete all test packages + '`basename $0`' -c -m -f PiAgerBackup_2020-01-22-07:02:17.img +' + +VALID_COMMAND_LINE_OPTIONS="clmhf:" +do_copy=false; +my_image=false; +last_backup=false; + +while getopts $VALID_COMMAND_LINE_OPTIONS options; do + #echo "option is " $options + case $options in + f) + source_file=${OPTARG} + ;; + l) + last_backup=true; + ;; + c) + do_copy=true; + ;; + m) + my_image=true; + ;; + h) + echo "$COMMAND_LINE_OPTIONS_HELP" + exit $E_OPTERROR; + ;; + \?) + echo "Usage: `basename $0` -h for help" + echo "$COMMAND_LINE_OPTIONS_HELP" + exit $E_OPTERROR; + ;; + *) + echo "$COMMAND_LINE_OPTIONS_HELP" + exit $E_OPTERROR; + ;; + esac +done +if [[ "$last_backup" = true ]] && [[ "$my_image" = true ]]; then + echo "Use Source_file with -f or Lastname -l for filename. Not the same!" + exit; +fi + +BACKUP_STATUS=$(ps ax | grep -v grep | grep pi-ager_backup.sh) +if [ -z "$BACKUP_STATUS" ] + then + echo "Backup ist inaktiv. Pi-Ager_image wird gestartet!" + else + echo "Backup ist aktiv. Pi-Ager_image wird nicht gestartet!" + exit 1 +fi + +#Überprüfen ob der NFS-Server vorhanden ist +echo "überprüfe ob der NFS-Server vorhanden ist." +echo "Checking..." +if [ -z "$NFSVOL" ] + then + echo "Backup nicht korrekt eingestellt. Bitte Tabelle nfs_backup prüfen!" + exit 1 + else + echo "$NFSVOL ist vorhanden" +fi + +# Überprüfen ob der Backup Pfad vorhanden ist +echo "überprüfe ob Backup Pfad vorhanden ist." +echo "Checking ..." +if [ -z "$BACKUP_PFAD" ] + then + echo "Backup Pfad nicht korrekt eingestellt. Bitte Tabelle nfs_backup prüfen!" + exit 1 + else + echo "$BACKUP_PFAD ist vorhanden" +fi + +#Überprüfen ob NFS Mount point in der Tabelle existiert +echo "überprüfe ob NFS Mount point definiert ist." +echo "Checking ..." +if [ -z "$NFSMOUNT" ] + then + echo "Kein NFS Mount point definiert. Bitte Tabelle nfs_backup prüfen!" + exit 1 + else + echo "$NFSMOUNT ist definiert" +fi + +echo "überprüfe ob NFS Mount point im file system angelegt ist." +echo "Checking..." +if [ -d "$NFSMOUNT" ] + then + echo "$NFSMOUNT ist angelegt" + else + echo "$NFSMOUNT wird angelegt" + sudo mkdir -p $NFSMOUNT + sudo chmod -R u=rwx,g+rw-x,o+rwx $NFSMOUNT + echo "$NFSMOUNT wurde angelegt" +fi + +# DIR=$NFSMOUNT/$SUBDIR + +echo "NFSVOL=$NFSVOL" +echo "NFSPATH=$BACKUP_PFAD" +echo "NFSMOUNT=$NFSMOUNT" + +# Vorsichtshalber einmal unmounten +umount $NFSMOUNT + +# NFS-Volume mounten +echo "hänge NFS-Volume $NFSVOL ein" + +# avoid warning that systemd still uses old version of fstab +systemctl daemon-reload + +if [ -n "$NFSOPT" ] + then + echo "mount with options: $NFSOPT" + mount -t nfs4 $NFSVOL $NFSMOUNT -o $NFSOPT + mountstatus=$? + else + echo "mount w/o options" + mount -t nfs4 $NFSVOL $NFSMOUNT + mountstatus=$? +fi + +if [ $mountstatus -ne 0 ]; then + echo "Error $mountstatus during mount NFS Volume $NFSVOL. Image script stopped." + exit 1 +else + echo "mount NFS-Volume $NFSVOL successfull. Image script continues." +fi + +# Prüfen, ob das Zielverzeichnis existiert +# echo "Prüfe ob das Zielverzeichnis existiert" +# sleep 2 +# if [ ! -d "$BACKUP_PFAD" ]; +# then +# echo "Backupverzeichnis existiert nicht. Abbruch! Bitte anlegen" +# umount $NFSMOUNT +# exit 1 +# else +# echo "Backupverzeichnis existiert = ${BACKUP_PFAD}" +# fi + +if [ "$last_backup" = true ] + then + echo "Load last backup file." + echo "Backup path is ${BACKUP_PFAD}" + Pi_Ager_backup=$(ls -ar $(find ${BACKUP_PFAD} -maxdepth 1 -type f) | grep "Backup" | head -n1) + + echo "Backup file is" $Pi_Ager_backup + source_file=$Pi_Ager_backup + echo "Backup path with file is" $source_file +fi + +if [ -z "${source_file}" ]; then + echo "$COMMAND_LINE_OPTIONS_HELP" +fi +if [[ ! -f "$source_file" ]]; then + echo "Source File $source_file not found!" + umount $NFSMOUNT + exit 1; +fi +echo "Source File = $source_file" +echo "do_copy = $do_copy" +echo "my_image = $my_image" + +if [ "$do_copy" = true ] + then + img_old="$source_file" + new_image="PiAger_image.img" + img=$BACKUP_PFAD/$new_image + echo "Coping $img_old to $img" + rsync -a --info=progress2 "$img_old" "$img" + else + img="$source_file" + echo "Using $img as source and target" +fi + +#read -p "Press enter to continue after copy image" +echo "####################################################################################" +parted_output=$(parted -ms "$img" unit B print | tail -n 1) +partnum=$(echo "$parted_output" | cut -d ':' -f 1) +partstart=$(echo "$parted_output" | cut -d ':' -f 2 | tr -d 'B') +loopback=$(losetup -f --show -o "$partstart" "$img") +echo "parted_output = $parted_output" +echo "partnum = $partnum" +echo "partstart = $partstart" +echo "loopback = $loopback" +echo "####################################################################################" +parted_output_boot=$(parted -ms "$img" unit B print | head -n3 | tail -n1) +partnum_boot=$(echo "$parted_output_boot" | cut -d ':' -f 1) +partstart_boot=$(echo "$parted_output_boot" | cut -d ':' -f 2 | tr -d 'B') +loopback_boot=$(losetup -f --show -o "$partstart_boot" "$img") +echo "parted_output_boot = $parted_output_boot" +echo "partnum_boot = $partnum_boot" +echo "partstart_boot = $partstart_boot" +echo "loopback_boot = $loopback_boot" +echo "####################################################################################" + +#read -p "Press enter to continue before image mount" +mountdir=$(mktemp -d) +echo "mount directory is ${mountdir}" + +mount ${loopback} ${mountdir} +#read -p "Press enter to continue after mounting $loopback to $mountdir" + +mount -t vfat -o shortname=winnt "$loopback_boot" "$mountdir/boot" + +###################################################### +# rewrite /boot/setup.txt, remove /boot/setup.log +###################################################### + +# echo "boot dir = $mountdir/boot " +# ls -al $mountdir/boot +rm $mountdir/boot/setup.txt +rm $mountdir/boot/setup.log +cd /tmp +wget -O setup.txt -nv https://raw.githubusercontent.com/Tronje-the-Falconer/Pi-Ager/entwicklung/RPi5/boot/firmware/setup.txt +mv setup.txt $mountdir/boot/setup.txt +echo "setup.txt copied to $mountdir/boot/" + +#read -p "Press enter to continue after mounting $loopback_boot $mountdir/boot" +#echo "Copy $mountdir/boot.bak/ to $mountdir/boot/" +#rsync -a --info=progress2 "$mountdir/boot.bak/" "$mountdir/boot/" +#read -p "Press enter to continue after copy boot.bak to boot" + +for i in dev proc sys dev/pts +do + mount -o bind /$i $mountdir/$i +done +#read -p "Press enter to continue after mount dev sys ..." + +regex='(\/.*\/)(.*)' +[[ $mountdir =~ $regex ]] + +echo "rematch1 ${BASH_REMATCH[1]}" +echo "rematch2 ${BASH_REMATCH[2]}" + +chrootdir=${BASH_REMATCH[2]} +echo "change rootdir is ${chrootdir}" +cd ${BASH_REMATCH[1]} +pwd +chroot $chrootdir /bin/bash < /root/.bash_history +cat /dev/null > /home/pi/.bash_history + + +# remove obsolete direcectories after upgrade +# rm -f /boot.bak +# rm -f /lib/modules.bak +# PRUNE_MODULES=1 sudo rpi-update + +systemctl disable pi-ager_main.service +echo "pi-ager_main.service disabled, will be enabled during setup_pi-ager.sh" +systemctl enable setup_pi-ager.service +echo "setup_pi-ager service enabled" + +#systemctl daemon-reload +#systemctl reset-failed + + +#****************************************************** +# Change some settings +#****************************************************** + +###################################################### +# Remove System key for encrypt/decrypt +###################################################### +rm -f /home/pi/system_key.bin + +###################################################### +# change hostname +###################################################### +raspi-config nonint do_hostname pi-ager +echo "hostname changed to pi-ager" + +# rewrite /var/.htcredentials +# mv /var/.htcredentials.org /var/.htcredentials + +###################################################### +# rewrite /etc/wpa_supplicant/wpa_supplicant.conf +###################################################### +# mv /etc/wpa_supplicant/wpa_supplicant.conf.org /etc/wpa_supplicant/wpa_supplicant.conf +# remove all wlan connections +# rm -f /etc/NetworkManager/system-connections/* + +##################################################### +#Force password change for user root +###################################################### +#change -d 0 root + +###################################################### +# SQLite3 changes +###################################################### + +sqlite3 /var/www/config/pi-ager.sqlite3 </etc/crontabtemp ; mv -f /etc/crontabtemp /etc/crontab # sed sucht | -n abstellen von ausgabe auf Konsole +echo +echo "------------------------------------------------------" +echo "Config Start" +echo "------------------------------------------------------" + +if [ -e /boot/firmware/setup.txt ] #wenn setup.txt existiert +then + echo "Setup.txt exists, getting variables" + eval $(grep -i "^piname=" /boot/firmware/setup.txt| tr -d "\n\r") + eval $(grep -i "^pipass=" /boot/firmware/setup.txt| tr -d "\n\r") + eval $(grep -i "^rootpass=" /boot/firmware/setup.txt| tr -d "\n\r") + eval $(grep -i "^webguipw=" /boot/firmware/setup.txt| tr -d "\n\r") + eval $(grep -i "^dbpw=" /boot/firmware/setup.txt| tr -d "\n\r") + eval $(grep -i "^wlanssid=" /boot/firmware/setup.txt| tr -d "\n\r") + eval $(grep -i "^wlankey=" /boot/firmware/setup.txt| tr -d "\n\r") + eval $(grep -i "^country=" /boot/firmware/setup.txt| tr -d "\n\r") + eval $(grep -i "^keepconf=" /boot/firmware/setup.txt| tr -d "\n\r") + eval $(grep -i "^sensor=" /boot/firmware/setup.txt | tr -d "\n\r") + eval $(grep -i "^hmidisplay=" /boot/firmware/setup.txt | tr -d "\n\r") + eval $(grep -i "^sensor=" /boot/firmware/setup.txt | tr -d "\n\r") + echo "Variablen" + echo "Hostname = $piname" + #echo $pipass + #echo $rootpass + #echo $webguipw + echo "WLAN SSID = $wlanssid" + echo "Country = $country" + #echo $wlankey + echo "Config behalten = $keepconf" + echo "sensor = $sensor" + echo "hmidisplay = $hmidisplay" + + echo "SSH Host Key generieren" + # SSH Host Key generieren + /bin/rm -fv /etc/ssh_host_* + #/usr/sbin/dpkg-reconfigure openssh-server + systemctl restart ssh.service + # pi Rechnername setzen + if [ -n "$piname" ] #wenn nicht "" + then + # CURRENT_HOSTNAME=`cat /etc/hostname | tr -d " \t\n\r"` + # echo -n $piname > /etc/hostname + # sed -i "s/127.0.1.1.*$CURRENT_HOSTNAME/127.0.1.1\t$piname/g" /etc/hosts + raspi-config nonint do_hostname $piname + echo "Hostname gesetzt" + fi + + # pi pass setzen + if [ -n "$pipass" ] #wenn nicht "" + then + echo "pi:$pipass" | chpasswd + echo "Passwort pi gesetzt" + fi + + # root pass setzen + if [ -n "$rootpass" ] #wenn nicht "" + then + echo "root:$rootpass" | chpasswd + echo "Passwort root gesetzt" + fi + + # phpliteadmin pass setzen + if [ -n "$dbpw" ] #wenn nicht "" + then + sed -i "s/raspberry/$dbpw/g" /var/www/phpliteadmin.config.php + echo "phpliteadmin.config.php gesetzt" + fi + + # settings pass setzen oder direkt mit https://websistent.com/tools/htdigest-generator-tool/ + if [ -n "$webguipw" ] #wenn nicht "" + then + user="pi-ager" + realm="Pi-Ager" + digest="$( printf "%s:%s:%s" "$user" "$realm" "$webguipw" | md5sum | awk '{print $1}' )" + + rm /var/.htcredentials + echo "$user:$realm:$digest" > /var/.htcredentials + echo "Passwort webgui gesetzt" + fi + + # wlan Netz und Key eintragen + # remove old profiles but not PI_AGER_ap.nmconnection + # rfkill unblock wifi + mv /etc/NetworkManager/system-connections/PI_AGER_AP.nmconnection /etc/NetworkManager/system-connections/PI_AGER_AP.nmconnection.org + rm /etc/NetworkManager/system-connections/*.nmconnection + mv /etc/NetworkManager/system-connections/PI_AGER_AP.nmconnection.org /etc/NetworkManager/system-connections/PI_AGER_AP.nmconnection + # systemctl restart NetworkManager + if [ -n "$wlanssid" ] #wenn nicht "" + then + if [ ${#wlankey} -ge 8 ] # 8 Zeichen oder mehr + then + # echo "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev" > /etc/wpa_supplicant/wpa_supplicant.conf + # echo "update_config=1" >> /etc/wpa_supplicant/wpa_supplicant.conf + # echo "country=$country" >> /etc/wpa_supplicant/wpa_supplicant.conf + # wpa_passphrase "$wlanssid" "$wlankey" >> /etc/wpa_supplicant/wpa_supplicant.conf + # echo -e "\nnetwork={\n\tssid=\x22${wlanssid}\x22\n\tpsk=\x22${wlankey}\x22\n\tkey_mgmt=WPA-PSK\n}" >> /etc/wpa_supplicant/wpa_supplicant.conf + raspi-config nonint do_wifi_country $country + echo "raspi-config do_wifi_country setup finished" + # raspi-config nonint do_wifi_ssid_passphrase "$wlanssid" "$wlankey" + # nmcli device wifi connect "$wlanssid" password "$wlankey" ifname wlan0 + nmFilename='/etc/NetworkManager/system-connections/pi-ager-wlan.nmconnection' + cat < "$nmFilename" +[connection] +id=pi-ager-wlan +uuid= +type=wifi +interface-name=wlan0 +timestamp= +autoconnect=true + +[wifi] +mode=infrastructure +ssid= + +[wifi-security] +auth-alg=open +key-mgmt=wpa-psk +psk= + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +method=auto + +[proxy] +EOF + chmod -R 600 "$nmFilename" + chown -R root:root "$nmFilename" + uuid=$(uuidgen) + timestamp=$(date +%s) + modify_nmconnection "$nmFilename" "$wlanssid" "$wlankey" "$uuid" "$timestamp" + if [ $? -eq 0 ] + then + echo "WLAN SSID und Passphrase gesetzt" + else + echo "Fehler $? : WLAN SSID und Passphrase konnten nicht gesetzt werden" + fi + fi + fi + + # Configfile löschen + if [ -z "$keepconf" ] #wenn "" + then + rm /boot/firmware/setup.txt + echo "Config gelöscht" + fi + +# check sensor + sensorbus=0 + sensornum=5 + case $sensor in + "DHT11") sensorbus=1; sensornum=1;; + "DHT22") sensorbus=1; sensornum=2;; + "SHT75") sensorbus=1; sensornum=3;; + "SHT85") sensorbus=0; sensornum=4;; + "SHT3x") sensorbus=0; sensornum=5;; + "SHT3x-mod") sensorbus=0; sensornum=6;; + "AHT1x") sensorbus=0; sensornum=7;; + "AHT1x-mod") sensorbus=0; sensornum=8;; + "AHT2x") sensorbus=0; sensornum=9;; + "AHT30") sensorbus=0; sensornum=10;; + "AHT4x-A") sensorbus=0; sensornum=11;; + "AHT4x-B") sensorbus=0; sensornum=12;; + "AHT4x-C") sensorbus=0; sensornum=13;; + esac + echo "Bus = $sensorbus sensor = $sensornum" + + if [ -n "$sensornum" ] # wenn nicht "" + then + sqlite3 /var/www/config/pi-ager.sqlite3 "PRAGMA journalMode = wal; UPDATE config SET value=$sensorbus WHERE key='sensorbus';" + sqlite3 /var/www/config/pi-ager.sqlite3 "PRAGMA journalMode = wal; UPDATE config SET value=$sensornum WHERE key='sensortype';" + echo "sensorbus und sensornum in DB gesetzt" + fi + + if [ $sensorbus -eq 0 ]; then + # hier muss alles hin was vor dem shutdown gemacht werden soll, um auf i2c zu wechseln + # rm -f /etc/modprobe.d/Pi-Ager_i2c_off.conf + echo "i2c is active" + elif [ $sensorbus -eq 1 ]; then + # hier muss alles hin was vor dem shutdown gemacht werden soll, um auf 1wire zu wechseln + # cp /etc/modprobe.d/Pi-Ager_i2c_off.conf.on /etc/modprobe.d/Pi-Ager_i2c_off.conf + echo "1-wire is active" + + fi + +# load firmware into HMI display if hmidisplay != "none" + case $hmidisplay in + "NX3224K028") echo "start firmware upload for HMI display device $hmidisplay" + nextion-fw-upload /dev/serial0 /var/www/nextion/NX3224K028/pi-ager.tft + echo "firmware upload for HMI device finished";; + "NX3224T028") echo "start firmware upload for HMI display device $hmidisplay" + nextion-fw-upload /dev/serial0 /var/www/nextion/NX3224T028/pi-ager.tft + echo "firmware upload for HMI device finished";; + "NX3224F028") echo "start firmware upload for HMI display device $hmidisplay" + nextion-fw-upload /dev/serial0 /var/www/nextion/NX3224F028/pi-ager.tft + echo "firmware upload for HMI device finished";; + esac +fi + +echo "disable setup_pi-ager.service now" +systemctl disable setup_pi-ager.service # Setupscript in Startroutine deaktivieren, da es nur beim ersten Start benötigt wird. + +# now its time to enable pi-ager_main.service to start at next boot. Reboot is initiated by rc.local after expanding file system on root partition +systemctl enable pi-ager_main.service + +exit 0 diff --git a/RPi5/var/www/admin.php b/RPi5/var/www/admin.php new file mode 100644 index 000000000..f564cb990 --- /dev/null +++ b/RPi5/var/www/admin.php @@ -0,0 +1,1269 @@ + +

+
+
+ + + + + + + + '; + echo ''; + echo ''; + } + else{ + echo ''; + echo ''; + echo ''; + } + ?> + +
' . _('uv light manual off') . '' . _('auto mode on') . '
+
+
+
+

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +


+

+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+
+
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+
+
>
+ + +

+
'; ?> + +

+ + + + + +

+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +


1

:>
:>
:>
:>
>
>
>
>

2

:>
:>
:>
:>
>
>
>
>
+ +

+
'; ?> + +

+
+ + + + + + + + + + + + + + + + + + + + + + + > + + + + > + + + + > + + + +


: + '; + foreach($meat_sensors as $meatsensor_row) + { + if (strncmp($meatsensor_row['name'], 'LEM', 3) !== 0) + { + if ($meatsensor_row['id'] == $meatsensor_index) + { + echo ''; + } + else + { + echo ''; + } + } + } + echo ''; + } + ?> +
: + '; + foreach($meat_sensors as $meatsensor_row) + { + if (strncmp($meatsensor_row['name'], 'LEM', 3) !== 0) + { + if ($meatsensor_row['id'] == $meatsensor_index) + { + echo ''; + } + else + { + echo ''; + } + } + } + echo ''; + } + ?> +
: + '; + foreach($meat_sensors as $meatsensor_row) + { + if (strncmp($meatsensor_row['name'], 'LEM', 3) !== 0) + { + if ($meatsensor_row['id'] == $meatsensor_index) + { + echo ''; + } + else + { + echo ''; + } + } + } + echo ''; + } + ?> +
: + '; + foreach($meat_sensors as $meatsensor_row) + { + if ($meatsensor_row['id'] == $meatsensor_index) + { + echo ''; + } + else + { + echo ''; + } + } + echo ''; + } + $current_check_row = get_table_row($config_current_check_table, 1); + $status_current_check = intval($current_check_row[$current_check_active_field]); + $current_threshold = number_format(floatval($current_check_row[$current_threshold_field]), 2, '.', ''); + $repeat_event_cycle = intval($current_check_row[$repeat_event_cycle_field]); + if ($status_current_check == 1) { + $cooler_relay_check_active_true = "checked"; + } + else{ + $cooler_relay_check_active_true = ""; + } + ?> +
 
+ + + + +

+
'; ?> + +

+
+ + + + + + +


+
+ />
+ />
+
+
+ +

+
'; ?> + +

+
+ + + + + + + + + + + + + + + +


 
: + +
: + +
 
+ +

+
'; ?> + +

+ + + + + +
+
+
+
+ +

+ +
+
+ + + + + + + + + + + + + + + + + + + + + +


:> Â°C (1 22)
: (1 24)
: + + /> +
 
: + + /> +
 
+ + +

+
'; ?> + +

+ + + + +
+
+
+
+ +

+ +
+
+ + + + + +
+
+
+
+

+ +
+ +
+ +
+ +

+ +
+
+ '; + echo '

' . _('debug values') . '

'; + /* */ + echo '
'; + echo '
'; + echo ''; + $agingtable_hours_in_seconds_debug = get_table_value($debug_table, $agingtable_hours_in_seconds_debug_key); + echo ''; + echo ''; + echo ''; + echo ''; + echo '
' . _('agingtable hours in seconds') . ':
'; + echo ''; + echo '
'; + echo '
'; + } + ?> +
+

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
:>
:>
:>
:
: + + /> +
+ +
+ + + + '; + } + else{ + echo ''; + } + ?> + + +
' . _('Agingtable is active. No backup possible!') . '
+ + + + + +
+ +
+ + +

+
'; ?> + +

+
+
+ +

+ +
+ + + + + + + +
+
+ +
+

+ +
+
+ + + + + +


+ />
+ />
+ />
+
+
+ +
+
+ + + + + + + +
+ +
+ +
+ +
+ + + +
+ +
+ + + + + + + +
+ + + + + +
+ + + +
+ +
+ +

+
'; ?> + +

+ +
+ + + + format($format) == $date; + } + + if (isset ($_POST['setdatetime'])){ + $newdatetime = $_POST['newdatetime']; + if (validateDate($newdatetime) == true) { + shell_exec('sudo /var/sudowebscript.sh set_time_date ' . '"' . $newdatetime . '"'); + echo ''; + } + else { + echo ''; + } + } + // $essid = exec("iwgetid | awk -F'\"' '{print $2}'"); + // echo 'ESSID : ' . $essid . "
"; + $ap_mode = false; + $local_ip = $_SERVER['REMOTE_ADDR']; + // echo 'local ip : ' . $local_ip . '
'; + if (strpos($local_ip, '10.0.0') !== false) { + $ap_mode = true; + // echo 'ap_mode : ' . $ap_mode . '
'; + } + // $hostname = ''; + // $addresses = exec("hostname -I"); + // echo 'hostname -I : ' . $addresses . '
'; + + // if (strpos($addresses, '10.0.0.1') !== false) { + // $ap_mode = true; + // echo 'ap_mode : ' . $ap_mode . '
'; + // } + // $address_list = explode(" ", $addresses); + // $address_list_count = count($address_list); + // if ($address_list_count == 0) { + // $hostname = ""; + // } + // else { + // $hostname = $address_list[0]; + // } + // $hostname = exec("hostname -I"); + // echo 'hostname -I : ' . $hostname . '
'; + // if ($local_ip !== '10.0.0.5') { + // if ($essid === 'RPiHotspot') { + ?> +
> +
+

+ +
+
+ + + + +
+
+ +
+
+
+ + +
> +
+

+ &1'); + $ssid_count = count($ssids_with_signal); + # echo 'return status from show_wifi_connections : ' . $res . '
'; + # var_dump($ssids); + $ssids_signals = array(); + foreach ($ssids_with_signal as $ssid_with_signal) { + $ssids_signals[] = explode(':', $ssid_with_signal); + } + } + ?> +
+ + + + +
+ +
+ +
+ + + + + +
+ '; + if ($si == 0) { + echo ''; + } + else { + echo ''; + } + echo ''; + echo ''; + echo ''; + } + $si++; + } + } + ?> + + + + +
SSIDSIGNAL
+
+ +
required>


+ +

+
+
+
' . $ssid_signal[1] . '

+
+
+
+ + + +
+ +

+ +
+
+ + + + +
+
+ +
+
+ + + + '; + echo '

' . _('python') . '

'; + /* */ + echo '
'; + echo '
'; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + // echo ''; + // echo ''; + echo ''; + // echo ''; + // echo ''; + echo ''; + echo '
'; + echo '
'; + echo '
'; + } + ?> + + + + + + + + + + + + diff --git a/RPi5/var/www/modules/read_all_gpio.php b/RPi5/var/www/modules/read_all_gpio.php new file mode 100644 index 000000000..13f1b9d92 --- /dev/null +++ b/RPi5/var/www/modules/read_all_gpio.php @@ -0,0 +1,53 @@ + $a == 'hi' ? 1 : 0 , $pin_status); + # var_dump($pin_status_int); + + $read_gpio_heater = $pin_status_int[0]; + $read_gpio_cooling_compressor = $pin_status_int[1]; + $read_gpio_dehumidifier = $pin_status_int[2]; + $read_gpio_light = $pin_status_int[3]; + $read_gpio_battery = $pin_status_int[4]; + $read_gpio_humidifier = $pin_status_int[5]; + $read_gpio_digital_switch = $pin_status_int[6]; + $read_gpio_exhausting_air = $pin_status_int[7]; + $read_gpio_circulating_air = $pin_status_int[8]; + $read_gpio_uv = $pin_status_int[9]; + $read_gpio_voltage = $pin_status_int[10]; + +?> \ No newline at end of file diff --git a/RPi5/var/www/modules/read_all_index.php b/RPi5/var/www/modules/read_all_index.php new file mode 100644 index 000000000..80e7cd524 --- /dev/null +++ b/RPi5/var/www/modules/read_all_index.php @@ -0,0 +1,178 @@ + "DHT11", + 2 => "DHT22", + 3 => "SHT75", + 4 => "SHT85", + 5 => "SHT3x", + 6 => "SHT3x-mod", + 7 => "AHT1x", + 8 => "AHT1x-mod", + 9 => "AHT2x", + 10 => "AHT30", + 11 => "SHT4x-A", + 12 => "SHT4x-B", + 13 => "SHT4x-C"]; + + $SUPPORTED_SECOND_SENSOR_TYPES = [ 0 => "disabled", + 4 => "SHT85", + 5 => "SHT3x", + 6 => "SHT3x-mod", + 7 => "AHT1x", + 8 => "AHT1x-mod", + 9 => "AHT2x", + 10 => "AHT30", + 11 => "SHT4x-A", + 12 => "SHT4x-B", + 13 => "SHT4x-C", + 14 => "MiThermometer"]; + + $sensorname = $SUPPORTED_MAIN_SENSOR_TYPES[$sensortype]; + $sensorsecondname = $SUPPORTED_SECOND_SENSOR_TYPES[$sensorsecondtype]; + + $desired_maturity = read_agingtable_name_from_config(); + // Derzeitige Reife-Art, manuell oder nach Tabelle... + // $grepagingtable = shell_exec('sudo /var/sudowebscript.sh grepagingtable'); + $status_agingtable = intval(get_table_value($current_values_table, $status_agingtable_key)); + if ($status_agingtable == 1){ + $maturity_type = $desired_maturity; + } + else { + $maturity_type = _('none'); + } + + + #Schaltzustände setzen + if($read_gpio_cooling_compressor == 0) { + $cooler_on_off_png = 'images/icons/status_on_20x20.png'; + } + if($read_gpio_cooling_compressor == 1) { + $cooler_on_off_png = 'images/icons/status_off_20x20.png'; + } + if($read_gpio_heater == 0) { + $heater_on_off_png = 'images/icons/status_on_20x20.png'; + } + if($read_gpio_heater == 1) { + $heater_on_off_png = 'images/icons/status_off_20x20.png'; + } + if($read_gpio_circulating_air == 0) { + $circulating_on_off_png = 'images/icons/status_on_20x20.png'; + } + if($read_gpio_circulating_air == 1) { + $circulating_on_off_png = 'images/icons/status_off_20x20.png'; + } + if($read_gpio_exhausting_air == 0) { + $exhausting_on_off_png = 'images/icons/status_on_20x20.png'; + } + if($read_gpio_exhausting_air == 1) { + $exhausting_on_off_png = 'images/icons/status_off_20x20.png'; + } + if($read_gpio_humidifier == 0) { + $humidifier_on_off_png = 'images/icons/status_on_20x20.png'; + } + if($read_gpio_humidifier == 1) { + $humidifier_on_off_png = 'images/icons/status_off_20x20.png'; + } + if($read_gpio_uv == 0) { + $uv_on_off_png = 'images/icons/status_on_20x20.png'; + } + if($read_gpio_uv == 1) { + $uv_on_off_png = 'images/icons/status_off_20x20.png'; + } + if($read_gpio_light == 0) { + $light_on_off_png = 'images/icons/status_on_20x20.png'; + } + if($read_gpio_light == 1) { + $light_on_off_png = 'images/icons/status_off_20x20.png'; + } + if($read_gpio_dehumidifier == 0) { + $dehumidifier_on_off_png = 'images/icons/status_on_20x20.png'; + } + if($read_gpio_dehumidifier == 1) { + $dehumidifier_on_off_png = 'images/icons/status_off_20x20.png'; + } + + if($status_agingtable == 0) { + $agingtable_on_off_png = 'images/icons/status_off_20x20.png'; + } + else { + $agingtable_on_off_png = 'images/icons/status_on_20x20.png'; + } + if($status_main == 0) { + $pi_ager_on_off_png = 'images/icons/status_off_20x20.png'; + } + else { + $pi_ager_on_off_png = 'images/icons/status_on_20x20.png'; + } + + $modus = intval(get_table_value($config_settings_table,$modus_key)); + $modus_name = ''; + if ($modus == 0) { + $modus_name = '- '._('cooling'); + } + else if ($modus == 1) { + $modus_name = '- '._('cooling').'
- '._('humidify'); + } + else if ($modus == 2) { + $modus_name = '- '._('heating').'
- '._('humidify'); + } + else if ($modus == 3) { + $modus_name = '- '._('cooling').'
- '._('heating').'
- '._('humidify'); + } + else if ($modus == 4) { + $modus_name = '- '._('cooling').'
- '._('heating').'
- '._('humidify').'
- '._('dehumidify').'
- '._('circulating air').'
- '._('exhausting air'); + } + + $sensor_temperature = number_format(floatval(get_table_value($current_values_table,$sensor_temperature_key)), 1, '.', ''); + $setpoint_temperature = number_format(floatval(get_table_value($config_settings_table,$setpoint_temperature_key)), 1, '.', ''); + + $cooling_hysteresis = get_table_value($config_settings_table ,$cooling_hysteresis_key); + $heating_hysteresis = get_table_value($config_settings_table ,$heating_hysteresis_key); + + $sensor_humidity = round(get_table_value($current_values_table,$sensor_humidity_key), 0); + $setpoint_humidity = round(get_table_value($config_settings_table,$setpoint_humidity_key), 0); + $humidifier_hysteresis = intval(get_table_value($config_settings_table,$humidifier_hysteresis_key)); + $dehumidifier_hysteresis = intval(get_table_value($config_settings_table,$dehumidifier_hysteresis_key)); + $hysteresis_offset = round(get_table_value($config_settings_table,$hysteresis_offset_key), 1); + $saturation_point = get_table_value($config_settings_table, $saturation_point_key); + $dehumidifier_modus = intval(get_table_value($config_settings_table,$dehumidifier_modus_key)); + $dewpoint_check = intval(get_table_value($config_settings_table, $dewpoint_check_key)); + + $circulation_air_duration = round(get_table_value($config_settings_table,$circulation_air_duration_key), 1)/60; + $circulation_air_period = round(get_table_value($config_settings_table,$circulation_air_period_key), 1)/60; + $exhaust_air_duration = round(get_table_value($config_settings_table,$exhaust_air_duration_key), 1)/60; + $exhaust_air_period = round(get_table_value($config_settings_table,$exhaust_air_period_key), 1)/60; + + $uv_modus = intval(get_table_value($config_settings_table,$uv_modus_key)); + $uv_duration = intval(get_table_value($config_settings_table,$uv_duration_key)/60); + $uv_period = intval(get_table_value($config_settings_table,$uv_period_key)/60); + $status_uv_manual = intval(get_table_value($current_values_table, $status_uv_manual_key)); + + $light_modus = intval(get_table_value($config_settings_table,$light_modus_key)); + $light_duration = intval(get_table_value($config_settings_table,$light_duration_key)/60); + $light_period = intval(get_table_value($config_settings_table,$light_period_key)/60); + $status_light_manual = intval(get_table_value($current_values_table,$status_light_manual_key)); + + $scale1_thread_alive = intval(get_table_value($current_values_table, $scale1_thread_alive_key)); + $scale2_thread_alive = intval(get_table_value($current_values_table, $scale2_thread_alive_key)); + $status_scale1 = intval(get_table_value($current_values_table,$status_scale1_key)); + $status_scale2 = intval(get_table_value($current_values_table,$status_scale2_key)); + + logger('DEBUG', 'read_config_db performed'); +?> \ No newline at end of file diff --git a/RPi5/var/www/modules/read_gpio.php b/RPi5/var/www/modules/read_gpio.php new file mode 100644 index 000000000..a13438f73 --- /dev/null +++ b/RPi5/var/www/modules/read_gpio.php @@ -0,0 +1,96 @@ + diff --git a/RPi5/var/www/modules/write_bus.php b/RPi5/var/www/modules/write_bus.php new file mode 100644 index 000000000..38b9dae7d --- /dev/null +++ b/RPi5/var/www/modules/write_bus.php @@ -0,0 +1,111 @@ + alert("' . $msg . '\n' . _('Pi-Ager will be shutdown now. After the shutdown process is finished, you must put your Raspberry Pi device into power-off state and change your sensor wire connection!') . '"); window.location.href="shutdown.php"; '; + //header("Location: /shutdown.php"); + //shell_exec('sudo /var/sudowebscript.sh shutdown > /dev/null 2>&1 &'); + //die(); + } + + function do_reboot( $msg ) { + echo ''; + //header("Location: /reboot.php"); + //shell_exec('sudo /var/sudowebscript.sh reboot > /dev/null 2>&1 &'); + //die(); + } + + function check_allowed_sensor_selection($sensor_intern, $sensor_extern) { + $i2c_sensor_addr = [0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => 0x44, 5 => 0x44, 6 => 0x45, 7 => 0x38, 8 => 0x39, 9 => 0x38, 10 => 0x38, 11 => 0x44, 12 => 0x45, 13 => 0x46, 14 => NULL]; + if ($sensor_extern == 14 || $sensor_extern == 0) { + return ( true); + } + if (($sensor_intern >= 1 && $sensor_intern <= 3) && ($sensor_extern >= 4 && $sensor_extern <= 13)) { + return( false ); + } + if ($i2c_sensor_addr[$sensor_intern] == $i2c_sensor_addr[$sensor_extern]) { // same i2c address, not allowed + return(false); + } + else { + return(true); + } + } + + + if (!empty($_POST['change_sensorbus_submit'])) { // ist das $_POST-Array gesetzt + logger('DEBUG', 'button save change_sensorbus pressed'); + unset($_POST['change_sensorbus_submit']); + + $old_sensorsecondtype = get_table_value($config_settings_table, $sensorsecondtype_key); + $old_sensornum = get_table_value($config_settings_table, $sensortype_key); + $old_ATC_device_name = get_table_value_from_field('atc_device_name', NULL, 'name'); + + $atc_device_name_changed = false; + + $old_bus = $_POST['bus']; + $sensornum = $_POST['sensortype_admin']; + $sensorsecondnum = $_POST['sensorsecondtype_admin']; + # echo "sensornum = " . $sensornum . ", second = " . $sensorsecondnum . "
"; + if (isset($_POST['atc_device_name'])) { + $ATC_device_name = $_POST['atc_device_name']; + write_table_value('atc_device_name', 'id', '1', 'name', $ATC_device_name); + if ($old_ATC_device_name !== $ATC_device_name) { + $atc_device_name_changed = true; + } + } + + # check if combination of sensor selections is allowed + $check_status = check_allowed_sensor_selection($sensornum, $sensorsecondnum); + if ($check_status == false) { + echo ''; + } + else { + # save new settings + write_sensorvalue($sensornum); + write_sensorsecondvalue($sensorsecondnum); + logger('DEBUG', 'sensortype saved'); + + # check if sensor changed + if ($old_sensornum != $sensornum) { # primary sensor changed, check if 1-wire or i2c interface must change + if (($sensornum == 1 || $sensornum == 2 || $sensornum == 3) && $old_bus == 0){ + //echo ''; + write_busvalue(1); + logger('DEBUG', 'sensorbus saved. changed to 1-wire (1)'); + // shell_exec('sudo /var/sudowebscript.sh sensorbus1wire > /dev/null 2>&1'); + do_shutdown(_('Change to 1-wire sensor')); + } + if (($sensornum >= 4 && $sensornum <= 13 ) && $old_bus == 1){ + //echo ''; + write_busvalue(0); + logger('DEBUG', 'sensorbus saved. changed to i2c (0)'); + // shell_exec('sudo /var/sudowebscript.sh sensorbusi2c > /dev/null 2>&1'); + do_shutdown(_('Change to I2C sensor')); + } + logger('DEBUG', 'internal sensor changed'); + do_shutdown(_('Internal sensor changed')); + } + + # check if external sensor changed + if ($old_sensorsecondtype != $sensorsecondnum) { # external sensor changed + // echo ''; + $boot_msg = _('External sensor type changed'); + logger('DEBUG', 'External sensor type changed'); + if ($sensorsecondnum == 0 || $sensorsecondnum == 14) { # changed back to disabled or MiThermometer, reboot is enough + do_reboot($boot_msg); + } + else { + do_shutdown($boot_msg); + } + } + + # at last check if only ATC_xxxxxx device has changed + if ($atc_device_name_changed == true) { + logger('DEBUG', 'ATC device name changed'); + } + else { + echo ''; + } + } + } +?> diff --git a/boot/firmware/cmdline.txt b/boot/firmware/cmdline.txt new file mode 100644 index 000000000..bcbcf8bf7 --- /dev/null +++ b/boot/firmware/cmdline.txt @@ -0,0 +1 @@ +console=tty1 root=PARTUUID=1a539695-02 rootfstype=ext4 fsck.repair=yes rootwait dwc_otg.fiq_fsm_mask=0x3 cfg80211.ieee80211_regdom=DE \ No newline at end of file diff --git a/boot/firmware/config.txt b/boot/firmware/config.txt new file mode 100644 index 000000000..6b342010f --- /dev/null +++ b/boot/firmware/config.txt @@ -0,0 +1,60 @@ +# For more options and information see +# http://rptl.io/configtxt +# Some settings may impact device functionality. See link above for details + +# Uncomment some or all of these to enable the optional hardware interfaces +#dtparam=i2c_arm=on +#dtparam=i2s=on +#dtparam=spi=on + +# --------------------- pi-ager settings --------- +# Use Pi-Ager Pins 11/13 GPIO 17/27 for I2C +dtoverlay=i2c-gpio,bus=3,i2c_gpio_sda=17,i2c_gpio_scl=27 +# Use Pi-Ager Pin 16 for MCP3204 +dtoverlay=spi1-1cs,cs0_pin=16 +# ----------------------------------------------- + +# Enable audio (loads snd_bcm2835) +dtparam=audio=on + +# Additional overlays and parameters are documented +# /boot/firmware/overlays/README + +# Automatically load overlays for detected cameras +camera_auto_detect=1 + +# Automatically load overlays for detected DSI displays +display_auto_detect=1 + +# Automatically load initramfs files, if found +auto_initramfs=1 + +# Enable DRM VC4 V3D driver +dtoverlay=vc4-kms-v3d +max_framebuffers=2 + +# Don't have the firmware create an initial video= setting in cmdline.txt. +# Use the kernel's default instead. +disable_fw_kms_setup=1 + +# Disable compensation for displays with overscan +disable_overscan=1 + +# Run as fast as firmware / board allows +arm_boost=1 + +[cm4] +# Enable host mode on the 2711 built-in XHCI USB controller. +# This line should be removed if the legacy DWC2 controller is required +# (e.g. for USB device mode) or if USB support is not required. +otg_mode=1 + +[all] + +enable_uart=1 +# ------------------------------ pi-ager settings ----------------- +dtoverlay=miniuart-bt +# force_turbo=1 +# ----------------------------------------------------------------- + + diff --git a/boot/firmware/setup.txt b/boot/firmware/setup.txt new file mode 100644 index 000000000..7a27e1e59 --- /dev/null +++ b/boot/firmware/setup.txt @@ -0,0 +1,79 @@ +# Initial Konfiguration +# Pi-Ager + +# Standard Hostname Pi-Ager +# Standard Passwoerter für alle raspberry +# +# Nur ausgefüllte Werte werden gesetzt +# Die Variablennamen dürfen nicht verändert werden! +# Wenn die Werte Sonderzeichen wie /?}][{|@!"§$%&-_.:,;#+~* oder Leerzeichen enthalten, +# müssen die Werte in 'Single Quotes' gesetzt werden. 'Single Quotes' dürfen dann nicht +# Bestandteil des Wertes sein! +# +# Z.B.: wlankey='FRITZ!Box 7490 |&;()<>"\$`^~@{}.' +# +# Logfile setup.log wird unter Linux im Verzeichnis /boot/firmware/ angelegt, +# und unter Windows mit der SD-Card in einem USB Lesegerät im Drive 'bootfs' im Verzeichnis /. +# + +# Hostname, wie soll der Raspberry Pi im Netzwerk heissen: +piname='pi-ager' + +# Passwort für Benutzer pi: +pipass='raspberry' + +# Passwort für Benutzer root: +rootpass='raspberry' + +# Passwort für Benutzer pi-ager auf der Webiste settings, admin, webcam: +webguipw='raspberry' + +# Passwort für Zugriff auf Datenbankverwaltung phpliteadmin: +dbpw='raspberry' + +#-------------------------------------------------------------------------------- +# Pi-Ager funktioniert auch ohne Router und ohne Internet Verbindung, +# denn im Pi-Ager steht simultan neben einer Verbindung mit einem Internet Router +# ein Accesspoint zur Verfügung. +# Der Accesspoint kann via Smartphone oder Tablet erreicht werden. +# Der Pi-Ager Accesspoint hat die WLAN SSID 'pi-ager' mit dem Default-Passwort '1234567890'. +# Der Pi-Ager ist dann über die IP Adresse 10.0.0.1 via SSH ereichbar. +# Der Pi-Ager Webserver kann mit einem Browser unter der URL http://10.0.0.1/ erreicht werden. +# Bei der erstmaligen Verbindung zum Accesspoint erscheint auch ein 'captive portal' mit +# Hinweisen zum Setup einer Verbindung zu einem WLAN Router. +# Auf der ADMIN Seite können dann Datum und Uhrzeit gesetzt werden +# und auch die Parameter für einen WLAN Router (SSID und Password). +# Das Default-Passwort für den Accesspoint kann auf der ADMIN-Seite geändert werden. +# +# ACHTUNG +# Im Router bzw bei den WLAN Security Einstellungen sollte ein Verschlüsselungsverfahren +# WPA2(CCMP) oder WPA2+WPA3 ausgewählt werden, da sonst keine WLAN Verbindung zwischen +# Pi-Ager und Router bzw. Accesspoint aufgebaut werden kann. +# WPA wird nicht vom Pi-Ager unterstützt +#------------------------------------------------------------------------------- + +# WLAN Netzwerkname: +wlanssid='your WLAN SSID' + +# WLAN Schlüssel (mindesten 8 Zeichen): +wlankey='your WLAN key' + +# ISO code your country, e.g. DE, GB: +country='DE' + +# Temperature/Humidity sensor attached to pi-ager: +# Supported types are : DHT11, DHT22, SHT75, SHT85, SHT3x, SHT3x-mod, AHT1x, AHT1x-mod, AHT2x, AHT30, SHT4x-A, SHT4x-B, SHT4x-C +sensor='SHT3x' + +# hmi TFT display device Namen: +# gültige device Namen: NX3224K028 or NX3224T028 or NX3224F028 +# z.B. : hmidisplay='NX3224K028' +# Wenn hmidisplay definiert ist, wird die Firmware des hmi TFT Displays beim ersten Booten geflasht. +# Das Flashen des Displays dauert bis zu 5 Minuten, der Fortschritt des Flashens kann nur auf dem +# TFT-Display beobachtet werden. +# Während des Flashens sollte die Stromversorgung des Raspi nicht ausgeschaltet werden. +# +hmidisplay= + +# setup.txt nach boot löschen? leer lassen für löschen oder 1 für behalten +keepconf=1 diff --git a/boot/setup.txt b/boot/setup.txt deleted file mode 100644 index 33ee0c99c..000000000 --- a/boot/setup.txt +++ /dev/null @@ -1,46 +0,0 @@ -# Initial Konfiguration -# Pi-Ager - -# Standard Hostname rpi-Pi-Ager -# Standard Passwoerter für alle raspberry -# -# Nur ausgefüllte Werte werden gesetzt -# Die Variablennamen dürfen nicht verändert werden! -# Wenn die Werte Sonderzeichen wie /?}][{|@!"§$%&-_.:,;#+~* oder Leerzeichen enthalten, -# müssen die Werte in 'Single Quotes' gesetzt werden. 'Single Quotes' dürfen dann nicht -# Bestandteil des Wertes sein! -# -# Z.B.: wlankey='FRITZ!Box 7490 |&;()<>"\$`^~@€{}.' -# -# Logfile wird unter /boot/setup.log angelegt - -# Hostname, wie soll der Raspberry Pi im Netzwerk heissen: -piname= - -# Passwort für Benutzer pi: -pipass= - -# Passwort für Benutzer root: -rootpass= - -# Passwort für Benutzer pi-ager auf der Webiste settings, admin, webcam: -webguipw= - -# Passwort für Zugriff auf Datenbankverwaltung phpliteadmin: -dbpw= - -# WLAN Netzwerkname: -wlanssid= - -# WLAN Schlüssel (mindesten 8 Zeichen): -wlankey= - -# ISO code your country, e.g. DE, GB: -country= - -# Temperature/Humidity sensor attched to pi-ager: -# Supported types are : DHT11, DHT22, SHT75, SHT85, SHT3x -sensor= - -# setup.txt nach boot löschen? leer lassen für löschen oder 1 für behalten -keepconf=1 diff --git a/etc/crontab b/etc/crontab new file mode 100644 index 000000000..c89cc0be8 --- /dev/null +++ b/etc/crontab @@ -0,0 +1,22 @@ +# /etc/crontab: system-wide crontab +# Unlike any other crontab you don't have to run the `crontab' +# command to install the new version when you edit this file +# and files in /etc/cron.d. These files also have username fields, +# that none of the other crontabs do. + +SHELL=/bin/sh +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +# Example of job definition: +# .---------------- minute (0 - 59) +# | .------------- hour (0 - 23) +# | | .---------- day of month (1 - 31) +# | | | .------- month (1 - 12) OR jan,feb,mar,apr ... +# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat +# | | | | | +# * * * * * user-name command to be executed +17 * * * * root cd / && run-parts --report /etc/cron.hourly +25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) +47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly ) +52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly ) +# diff --git a/etc/modprobe.d/Pi-Ager_i2c_off.conf.on b/etc/modprobe.d/Pi-Ager_i2c_off.conf.on index badc49d09..ef981c538 100644 --- a/etc/modprobe.d/Pi-Ager_i2c_off.conf.on +++ b/etc/modprobe.d/Pi-Ager_i2c_off.conf.on @@ -1,6 +1,6 @@ # File for deactivate the i2c bus and use the 1wire bus on GPIO17 / GPIO27 # If this file has the extension .conf this modules are not loaded -blacklist spi-bcm2708 -blacklist i2c-bcm2708 +# blacklist spi-bcm2708 +# blacklist i2c-bcm2708 blacklist i2c-dev -blacklist i2c_algo_bit +# blacklist i2c_algo_bit diff --git a/etc/nodogsplash/htdocs/images/logo.png b/etc/nodogsplash/htdocs/images/logo.png new file mode 100644 index 000000000..5bd330665 Binary files /dev/null and b/etc/nodogsplash/htdocs/images/logo.png differ diff --git a/etc/nodogsplash/htdocs/images/splash.jpg b/etc/nodogsplash/htdocs/images/splash.jpg new file mode 100644 index 000000000..ac9a357a6 Binary files /dev/null and b/etc/nodogsplash/htdocs/images/splash.jpg differ diff --git a/etc/nodogsplash/htdocs/splash.css b/etc/nodogsplash/htdocs/splash.css new file mode 100644 index 000000000..7fbd045f8 --- /dev/null +++ b/etc/nodogsplash/htdocs/splash.css @@ -0,0 +1,98 @@ +body { + background-color: lightgrey; + color: black; + margin-left: 5%; + margin-right: 5%; + text-align: left; +} + +hr { + display:block; + margin-top:0.5em; + margin-bottom:0.5em; + margin-left:auto; + margin-right:auto; + border-style:inset; + border-width:5px; +} + +.offset { + background: rgba(300, 300, 300, 0.6); + margin-left:auto; + margin-right:auto; + max-width:600px; + min-width:200px; + padding: 5px; +} + +.insert +{ + background: rgba(350, 350, 350, 0.7); + border: 2px solid #aaa; + border-radius: 4px; + min-width:200px; + max-width:100%; + padding: 5px; + text-align: center; +} + +img { + width: 40%; + max-width: 180px; + margin-left: 0%; + margin-right: 5%; +} + +input[type=text], input[type=email], input[type=number] { + color: black; + background: white; + margin-left: 0%; + margin-right: 5%; + text-align: left; + font-size: 1.0em; + line-height: 2.0em; + font-weight: bold; + border: 3px; + border-style: inset; +} + +input[type=submit] { + color: white; + background: green; + margin-left: 0%; + margin-right: 5%; + text-align: left; + font-size: 1.0em; + line-height: 2.5em; + font-weight: bold; + border: 3px; + border-style: inset; +} + +med-blue { + font-size: 1.2em; + color: blue; + font-weight: bold; + font-style: normal; +} + +big-red { + font-size: 1.5em; + color: red; + font-weight: bold; +} + +italic-black { + font-size: 1.0em; + color: black; + font-weight: bold; + font-style: italic; +} + +copy-right { + font-size: 0.7em; + color: darkgrey; + font-weight: bold; + font-style:italic; +} + diff --git a/etc/nodogsplash/htdocs/splash.html b/etc/nodogsplash/htdocs/splash.html new file mode 100644 index 000000000..2adcbd6e3 --- /dev/null +++ b/etc/nodogsplash/htdocs/splash.html @@ -0,0 +1,97 @@ + + + + + + + + + + + + +$gatewayname Hotspot Gateway. + + + + + + +
+Pi-Ager Hotspot Gateway. +
+
+Splash Page: For access to the Internet, please click Continue. +
+Welcome! +
+
+For access to the pi-ager web pages, please tap or click Continue. This should open your internet browser showing the pi-ager MONITOR page index.php. If the MONITOR page is not shown, open your internet browser and put the IP address 10.0.0.1 or the domain name pi-ager into the address bar to open the pi-ager index.php page. From there select the ADMIN page, where it is possible to setup your WLAN authentication parameters SSID, WLAN password and country code. The ADMIN page asks for username/password, both are defined in the Pi-Ager setup.txt file. The default values are pi-ager/raspberry. +

+
+ +
+ + + + +
+ +
+Copyright © The Nodogsplash Contributors 2004-2019.
This software is released under the GNU GPL license.
+ +
+ + diff --git a/etc/nodogsplash/htdocs/splash.html.org b/etc/nodogsplash/htdocs/splash.html.org new file mode 100644 index 000000000..fd70e5261 --- /dev/null +++ b/etc/nodogsplash/htdocs/splash.html.org @@ -0,0 +1,97 @@ + + + + + + + + + + + + +$gatewayname Hotspot Gateway. + + + + + + +
+$gatewayname Hotspot Gateway. +
+
+Splash Page: For access to the Internet, please click Continue. +
+Welcome! +
+
+For access to the Internet, please tap or click Continue. +

+
+ +
+ + + + +
+ +
+Copyright © The Nodogsplash Contributors 2004-2019.
This software is released under the GNU GPL license.
+ +
+ + diff --git a/etc/nodogsplash/htdocs/status.html b/etc/nodogsplash/htdocs/status.html new file mode 100644 index 000000000..534baa3c3 --- /dev/null +++ b/etc/nodogsplash/htdocs/status.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + +$gatewayname Hotspot Gateway Status + + + + + + +
+$gatewayname Hotspot Gateway. +
+
+You are already logged in and have access to the Internet. +
+

You are already logged in and have access to the Internet.

+
+

You can use your Browser, Email and other network Apps as you normally would.

+ +
+Copyright © The Nodogsplash Contributors 2004-2019.
This software is released under the GNU GPL license.
+ +
+ + diff --git a/etc/nodogsplash/nodogsplash.conf b/etc/nodogsplash/nodogsplash.conf new file mode 100644 index 000000000..c1dbce701 --- /dev/null +++ b/etc/nodogsplash/nodogsplash.conf @@ -0,0 +1,388 @@ +# +# Nodogsplash Configuration File +# + +# Parameter: GatewayInterface +# Default: NONE +# +# GatewayInterface is not autodetected, has no default, and must be set here. +# Set GatewayInterface to the interface on your router +# that is to be managed by Nodogsplash. +# Typically br-lan for the wired and wireless lan. +# +GatewayInterface wlan1 + +# Parameter: WebRoot +# Default: /etc/nodogsplash/htdocs +# +# The local path where the splash page content resides. + +# FirewallRuleSet: authenticated-users +# +# Control access for users after authentication. +# These rules are inserted at the beginning of the +# FORWARD chain of the router's filter table, and +# apply to packets that have come in to the router +# over the GatewayInterface from MAC addresses that +# have authenticated with Nodogsplash, and that are +# destined to be routed through the router. The rules are +# considered in order, and the first rule that matches +# a packet applies to it. +# If there are any rules in this ruleset, an authenticated +# packet that does not match any rule is rejected. +# N.B.: This ruleset is completely independent of +# the preauthenticated-users ruleset. +# +FirewallRuleSet authenticated-users { + +# You may want to open access to a machine on a local +# subnet that is otherwise blocked (for example, to +# serve a redirect page; see RedirectURL). If so, +# allow that explicitly here, e.g: +# FirewallRule allow tcp port 80 to 192.168.254.254 + +# Your router may have several interfaces, and you +# probably want to keep them private from the GatewayInterface. +# If so, you should block the entire subnets on those interfaces, e.g.: +# FirewallRule block to 192.168.0.0/16 +# FirewallRule block to 10.0.0.0/8 + +# Typical ports you will probably want to open up include +# 53 udp and tcp for DNS, +# 80 for http, +# 443 for https, +# 22 for ssh: +# FirewallRule allow tcp port 53 +# FirewallRule allow udp port 53 +# FirewallRule allow tcp port 80 +# FirewallRule allow tcp port 443 +# FirewallRule allow tcp port 22 +# Or for happy customers allow all + FirewallRule allow all +# You might use ipset to easily allow/block range of ips, e.g.: +# FirewallRule allow ipset WHITELISTED_IPS +# FirewallRule allow tcp port 80 ipset WHITELISTED_IPS +} +# end FirewallRuleSet authenticated-users + + +# FirewallRuleSet: preauthenticated-users +# +# Control access for users before authentication. +# These rules are inserted in the PREROUTING chain +# of the router's nat table, and in the +# FORWARD chain of the router's filter table. +# These rules apply to packets that have come in to the +# router over the GatewayInterface from MAC addresses that +# are not on the BlockedMACList or TrustedMACList, +# are *not* authenticated with Nodogsplash. The rules are +# considered in order, and the first rule that matches +# a packet applies to it. A packet that does not match +# any rule here is rejected. +# N.B.: This ruleset is completely independent of +# the authenticated-users and users-to-router rulesets. +# +FirewallRuleSet preauthenticated-users { +# For preauthenticated users to resolve IP addresses in their +# initial request not using the router itself as a DNS server. +# Leave commented to help prevent DNS tunnelling + +# FirewallRule allow tcp port 53 +# FirewallRule allow udp port 53 + +# For splash page content not hosted on the router, you +# will want to allow port 80 tcp to the remote host here. +# Doing so circumvents the usual capture and redirect of +# any port 80 request to this remote host. +# Note that the remote host's numerical IP address must be known +# and used here. +# FirewallRule allow tcp port 80 to 123.321.123.321 +} +# end FirewallRuleSet preauthenticated-users + + +# FirewallRuleSet: users-to-router +# +# Control access to the router itself from the GatewayInterface. +# These rules are inserted at the beginning of the +# INPUT chain of the router's filter table, and +# apply to packets that have come in to the router +# over the GatewayInterface from MAC addresses that +# are not on the TrustedMACList, and are destined for +# the router itself. The rules are +# considered in order, and the first rule that matches +# a packet applies to it. +# If there are any rules in this ruleset, a +# packet that does not match any rule is rejected. +# +FirewallRuleSet users-to-router { + # Nodogsplash automatically allows tcp to GatewayPort, + # at GatewayAddress, to serve the splash page. + # However you may want to open up other ports, e.g. + # 53 for DNS and 67 for DHCP if the router itself is + # providing these services. + FirewallRule allow udp port 53 + FirewallRule allow tcp port 53 + FirewallRule allow udp port 67 + # You may want to allow ssh, http, and https to the router + # for administration from the GatewayInterface. If not, + # comment these out. + FirewallRule allow tcp port 22 + FirewallRule allow tcp port 80 + FirewallRule allow tcp port 443 +} +# end FirewallRuleSet users-to-router + +# EmptyRuleSetPolicy directives +# The FirewallRuleSets that NoDogSplash permits are: +# +# authenticated-users +# preauthenticated-users +# users-to-router +# trusted-users +# trusted-users-to-router +# +# For each of these, an EmptyRuleSetPolicy can be specified. +# An EmptyRuleSet policy applies to a FirewallRuleSet if the +# FirewallRuleSet is missing from this configuration file, +# or if it exists but contains no FirewallRules. +# +# The possible values of an EmptyRuleSetPolicy are: +# allow -- packets are accepted +# block -- packets are rejected +# passthrough -- packets are passed through to pre-existing firewall rules +# +# Default EmptyRuleSetPolicies are set as follows: +# EmptyRuleSetPolicy authenticated-users passthrough +# EmptyRuleSetPolicy preauthenticated-users block +# EmptyRuleSetPolicy users-to-router block +# EmptyRuleSetPolicy trusted-users allow +# EmptyRuleSetPolicy trusted-users-to-router allow + + +# Parameter: GatewayName +# Default: NoDogSplash +# +# Set GatewayName to the name of your gateway. This value +# will be available as variable $gatewayname in the splash page source +# and in status output from ndsctl, but otherwise doesn't matter. +# If none is supplied, the value "NoDogSplash" is used. +# +GatewayName Pi-Ager + +# Parameter: GatewayAddress +# Default: Discovered from GatewayInterface +# +# This should be autodetected on an OpenWRT system, but if not: +# Set GatewayAddress to the IP address of the router on +# the GatewayInterface. This is the address that the Nodogsplash +# server listens on. +# +GatewayAddress 10.0.0.1 + +# Parameter: StatusPage +# Default: status.html +# +# The page the client is show if the client is already authenticated but navigates to the captive portal. +# +# StatusPage status.html + +# Parameter: SplashPage +# Default: splash.html +# +# The page the client is redirected to if not authenticated or whitelisted. +# +# SplashPage splash.html + +# Parameter: RedirectURL +# Default: none +# +# After authentication, normally a user is redirected +# to their initially requested page. +# If RedirectURL is set, the user is redirected to this URL instead. +# +# RedirectURL http://pi-ager +RedirectURL http://10.0.0.1 + +# Parameter: GatewayPort +# Default: 2050 +# +# Nodogsplash's own http server uses GatewayAddress as its IP address. +# The port it listens to at that IP can be set here; default is 2050. +# +# GatewayPort 2050 + +# Parameter: MaxClients +# Default: 20 +# +# Set MaxClients to the maximum number of users allowed to +# connect at any time. (Does not include users on the TrustedMACList, +# who do not authenticate.) +# +# MaxClients 250 + +# Parameter: SessionTimeout +# Default: 0 +# +# Set the default session length in minutes. A value of 0 is for +# sessions without an end. +# +SessionTimeout 20 + +# Parameter: PreAuthIdleTimeout +# Default: 10 +# +# Set PreAuthIdleTimeout to the desired number of minutes before +# an pre-authenticated user is automatically removed from the client list. +# + +# Parameter: AuthIdleTimeout +# Default: 120 +# +# Set AuthIdleTimeout to the desired number of minutes before +# an authenticated user is automatically 'deauthenticated' +# and removed from the client list. +# +AuthIdleTimeout 20 + +# Parameter: CheckInterval +# Default: 30 +# +# Interval in seconds (!) the timeouts of all clients are checked. +# + +# Parameter: MACMechanism +# Default: block +# +# Either block or allow. +# If 'block', MAC addresses on BlockedMACList are blocked from +# authenticating, and all others are allowed. +# If 'allow', MAC addresses on AllowedMACList are allowed to +# authenticate, and all other (non-trusted) MAC's are blocked. +# +# MACMechanism block + +# Parameter: BlockedMACList +# Default: none +# +# Comma-separated list of MAC addresses who will be completely blocked +# from the GatewayInterface. Ignored if MACMechanism is allow. +# N.B.: weak security, since MAC addresses are easy to spoof. +# +# BlockedMACList 00:00:DE:AD:BE:EF,00:00:C0:1D:F0:0D + +# Parameter: AllowedMACList +# Default: none +# +# Comma-separated list of MAC addresses who will not be completely +# blocked from the GatewayInterface. Ignored if MACMechanism is block. +# N.B.: weak security, since MAC addresses are easy to spoof. +# +# AllowedMACList 00:00:12:34:56:78 + +# Parameter: TrustedMACList +# Default: none +# +# Comma-separated list of MAC addresses who are not subject to +# authentication, and are not restricted by any FirewallRuleSet. +# N.B.: weak security, since MAC addresses are easy to spoof. +# +# TrustedMACList 00:00:CA:FE:BA:BE, 00:00:C0:01:D0:0D + +# Parameter: TrafficControl +# Default: no +# +# Set to yes (or true or 1), to enable traffic control in Nodogsplash. +# +# TrafficControl no + +# Parameter: DownloadLimit +# Default: 0 +# +# If TrafficControl is enabled, this sets the maximum download +# speed to the GatewayInterface, in kilobits per second. +# For example if you have an ADSL connection with 768 kbit +# download speed, and you want to allow about half of that +# bandwidth for the GatewayInterface, set this to 384. +# A value of 0 means no download limiting is done. +# +# DownloadLimit 384 + +# Parameter: UploadLimit +# Default: 0 +# +# If TrafficControl is enabled, this sets the maximum upload +# speed from the GatewayInterface, in kilobits per second. +# For example if you have an ADSL connection with 128 kbit +# upload speed, and you want to allow about half of that +# bandwidth for the GatewayInterface, set this to 64. +# A value of 0 means no upload limiting is done. +# +# UploadLimit 64 + +# Parameter: GatewayIPRange +# Default: 0.0.0.0/0 +# +# By setting this parameter, you can specify a range of IP addresses +# on the GatewayInterface that will be responded to and managed by +# Nodogsplash. Addresses outside this range do not have their packets +# touched by Nodogsplash at all. +# Defaults to 0.0.0.0/0, that is, all addresses. +# +# GatewayIPRange 0.0.0.0/0 + +# Parameter: DebugLevel +# Default: 1 +# +# Set the debug level: +# 0: errors only +# 1: errors, warnings, infos +# 2: errors, warnings, infos, verbose messages +# 3: errors, warnings, infos, verbose messages, debug messages +# +# DebugLevel 1 + +# Parameter: BinAuth +# +# Enable BinAuth Support. +# If set, a program is called with several parameters on authentication (request) and deauthentication. +# +# Request for authentication: +# +# $ auth_client '' '' +# +# The username and password values may be empty strings and are URL encoded. +# The program is expected to output the number of seconds the client +# is to be authenticated. Zero or negative seconds will cause the authentification request +# to be rejected. The same goes for an exit code that is not 0. +# The output may contain a user specific download and upload limit in KBit/s: +# +# +# Called on authentication or deauthentication: +# $ <*auth|*deauth> +# +# "client_auth": Client authenticated via this script. +# "client_deauth": Client deauthenticated by the client via splash page. +# "idle_deauth": Client was deauthenticated because of inactivity. +# "timeout_deauth": Client was deauthenticated because the session timed out. +# "ndsctl_auth": Client was authenticated manually by the ndsctl tool. +# "ndsctl_deauth": Client was deauthenticated by the ndsctl tool. +# "shutdown_deauth": Client was deauthenticated by Nodogsplash terminating. +# +# Values session_start and session_start are in seconds since 1970 or 0 for unknown/unlimited. +# +# BinAuth /bin/myauth.sh + +# Nodogsplash uses specific HEXADECIMAL values to mark packets used by iptables as a bitwise mask. +# This mask can conflict with the requirements of other packages such as mwan3, sqm etc +# Any values set here are interpreted as in hex format. +# +# Parameter: fw_mark_authenticated +# Default: 30000 (0011|0000|0000|0000|0000 binary) +# +# Parameter: fw_mark_trusted +# Default: 20000 (0010|0000|0000|0000|0000 binary) +# +# Parameter: fw_mark_blocked +# Default: 10000 (0001|0000|0000|0000|0000 binary) +# diff --git a/etc/rc.local b/etc/rc.local new file mode 100644 index 000000000..b565e18c0 --- /dev/null +++ b/etc/rc.local @@ -0,0 +1,36 @@ +#!/bin/sh -e +# +# rc.local +# +# This script is executed at the end of each multiuser runlevel. +# value on error. +# +# In order to enable or disable this script just change the execution +# bits. +# +# By default this script does nothing. + +# Print the IP address +_IP=$(hostname -I) || true +if [ "$_IP" ]; then + printf "My IP address is %s\n" "$_IP" +fi +# start pi-ager +systemctl start pi-ager_main.service + +# disable power management for wlan0 to increase WLAN reliability +rfkill unblock wifi +sleep 1 +# iwconfig wlan0 power off +iw wlan0 set power_save off + +# enable AP-STA mode +iw dev wlan0 interface add wlan1 type __ap +sleep 1 + +iw wlan1 set power_save off + +# enable captive portal +nodogsplash + +exit 0 diff --git a/lib/systemd/system/pi-ager_agingtable.service b/lib/systemd/system/pi-ager_agingtable.service deleted file mode 100644 index 3d39ab40d..000000000 --- a/lib/systemd/system/pi-ager_agingtable.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Start agingtable routine of Pi-Ager -After=network.target - -[Service] -Type=simple -ExecStart=python3 /opt/pi-ager/agingtable.py 2>&1 -PIDFile=/tmp/pi-ager_agingtable.pid - -[Install] -Alias=pi-ager_agingtable -WantedBy=multi-user.target \ No newline at end of file diff --git a/lib/systemd/system/pi-ager_main.service b/lib/systemd/system/pi-ager_main.service index cd4efa265..7e7da0b53 100644 --- a/lib/systemd/system/pi-ager_main.service +++ b/lib/systemd/system/pi-ager_main.service @@ -12,5 +12,5 @@ StandardOutput=null StandardError=null [Install] -Alias=pi-ager +Alias=pi-ager.service WantedBy=multi-user.target \ No newline at end of file diff --git a/lib/systemd/system/pi-ager_scale.service b/lib/systemd/system/pi-ager_scale.service deleted file mode 100644 index b5473b61f..000000000 --- a/lib/systemd/system/pi-ager_scale.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Start scale routine of Pi-Ager -After=network.target - -[Service] -Type=simple -ExecStart=python3 /opt/pi-ager/scale.py 2>&1 -PIDFile=/tmp/pi-ager_scale.pid - -[Install] -Alias=pi-ager_scale -WantedBy=multi-user.target \ No newline at end of file diff --git a/lib/systemd/system/setup_pi-ager.service b/lib/systemd/system/setup_pi-ager.service index aa7e562a3..60a3f914e 100644 --- a/lib/systemd/system/setup_pi-ager.service +++ b/lib/systemd/system/setup_pi-ager.service @@ -1,13 +1,17 @@ [Unit] -Description=Automatsches Installationsscript für pi-ager zum Setzen von Passwörter und WIFI-Zugang, abhängig von setup.txt in /boot +Description=Automatsches Installationsscript für pi-ager zum Setzen von Passwörter und WIFI-Zugang, abhängig von setup.txt in /boot/firmware +# Before=rc-local.service lighttpd.service +# After=NetworkManager-wait-online.service +Before=rc-local.service +After=NetworkManager.service +# After=multi-user.target [Service] Type=oneshot ExecStart=/usr/local/bin/setup_pi-ager.sh -StandardOutput=append:/boot/setup.log -StandardError=append:/boot/setup.log +StandardOutput=append:/boot/firmware/setup.log +StandardError=append:/boot/firmware/setup.log [Install] -Alias=setup_pi-ager WantedBy=multi-user.target \ No newline at end of file diff --git a/opt/ATC_MiThermometer/ATC_db_helper.py b/opt/ATC_MiThermometer/ATC_db_helper.py new file mode 100644 index 000000000..30c700b03 --- /dev/null +++ b/opt/ATC_MiThermometer/ATC_db_helper.py @@ -0,0 +1,141 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +""" + database communication + functions for communication with the database +""" + +import sqlite3 +import time + +global cursor +global connection + +def get_current_time(): + """ + function for reading out the current time stamp + """ + current_time = int(time.time()) + return current_time + +def open_database(): + """ + function to open the database connection + """ + global cursor + global connection + """ + Changed due to database locked errors + -removed: connection = sqlite3.connect(pi_ager_paths.sqlite3_file) + + -added timeout = 5 (five seconds) + -enabled shared cache + -set isolation level to None + -set journal mode WAL + + See also + https://docs.python.org/2/library/sqlite3.html#sqlite3.Connection.isolation_level + + http://charlesleifer.com/blog/going-fast-with-sqlite-and-python/ + """ + + #Enable shared chache + sqlite3.enable_shared_cache(True) + # Open database in autocommit mode by setting isolation_level to None. + connection = sqlite3.connect('/var/www/config/pi-ager.sqlite3', isolation_level=None, timeout = 10) + # Set journal mode to WAL (Write-Ahead Log) + connection.execute('PRAGMA journal_mode = wal') + connection.execute('PRAGMA synchronous = OFF') + connection.execute('PRAGMA read_uncommitted = True') + + connection.row_factory = sqlite3.Row + cursor = connection.cursor() + +def execute_query(command): + """ + function for executing a SQL + """ + global cursor + global connection + + count = 0 + while True: + try: + cursor.execute(command) + connection.commit() + return + except Exception as cx_error: + count = count + 1 + time.sleep(1) + if (count == 3): + return #raise + +def close_database(): + """ + function for closing the database connection + """ + global connection + connection.close() + +def get_table_value_from_field(table, field): + """ + function to read a value to a known field with max(id) + """ + global cursor + + sql = 'SELECT ' + field + ' FROM ' + table + ' WHERE id = (SELECT MAX(id) FROM ' + table + ')' + value = None + + open_database() + execute_query(sql) + row = cursor.fetchone() + close_database() + if (row != None): + value = row[field] + return value + +def is_table_empty( table ): + """ + check if table is empty + return True, if empty, else False + """ + sql = 'SELECT COUNT(*) as count FROM ' + table + open_database() + execute_query(sql) + row = cursor.fetchone() + close_database() + if (row == None): + return True + numRows = row['count'] + if (numRows == 0): + return True + else: + return False + +def empty_table( table ): + """ + empty table and reset auto_inc counter + """ + sql1 = 'DELETE FROM ' + table + sql2 = 'DELETE FROM SQLITE_SEQUENCE WHERE name=' + table + open_database() + execute_query(sql1) + execute_query(sql2) + close_database() + +def write_atc_data( temperature, humidity, battvolt, battpercent, last_change): + """ + write Bluetooth MiTemp sensor data into DB + """ + if (is_table_empty('atc_data') == True): + sql = 'INSERT INTO atc_data (temperature,humidity,battvolt,battpercent,last_change, id) VALUES (' + str(temperature) + ',' + str(humidity) + ',' + str(battvolt) + ',' + str(battpercent) + ',' + str(last_change) + ',1' + ')' + else: + sql = 'UPDATE atc_data SET temperature = ' + str(temperature) + ',humidity = ' + str(humidity) + ',battvolt = ' + str(battvolt) + ',battpercent = ' + str(battpercent) + ',last_change = ' + str(last_change) + ' WHERE id = 1' + open_database() + execute_query(sql) + close_database() + + + + + \ No newline at end of file diff --git a/opt/ATC_MiThermometer/ATC_xxxxxx.py b/opt/ATC_MiThermometer/ATC_xxxxxx.py new file mode 100644 index 000000000..fa6118f13 --- /dev/null +++ b/opt/ATC_MiThermometer/ATC_xxxxxx.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python3 +from __future__ import print_function +import argparse +import binascii +import os +import sys +from bluepy import btle +import schedule +import time +import signal +import sqlite3 +import ATC_db_helper +import syslog +import traceback +from datetime import datetime + +# catch signal.SIGTERM and signal.SIGINT when killing main to gracefully shutdown system +def signal_handler(signum, frame): + do_cancel_job() + +if os.getenv('C', '1') == '0': + ANSI_RED = '' + ANSI_GREEN = '' + ANSI_YELLOW = '' + ANSI_CYAN = '' + ANSI_WHITE = '' + ANSI_OFF = '' +else: + ANSI_CSI = "\033[" + ANSI_RED = ANSI_CSI + '31m' + ANSI_GREEN = ANSI_CSI + '32m' + ANSI_YELLOW = ANSI_CSI + '33m' + ANSI_CYAN = ANSI_CSI + '36m' + ANSI_WHITE = ANSI_CSI + '37m' + ANSI_OFF = ANSI_CSI + '0m' + + +def dump_services(dev): + services = sorted(dev.services, key=lambda s: s.hndStart) + for s in services: + print ("\t%04x: %s" % (s.hndStart, s)) + if s.hndStart == s.hndEnd: + continue + chars = s.getCharacteristics() + for i, c in enumerate(chars): + props = c.propertiesToString() + h = c.getHandle() + if 'READ' in props: + val = c.read() + if c.uuid == btle.AssignedNumbers.device_name: + string = ANSI_CYAN + '\'' + \ + val.decode('utf-8') + '\'' + ANSI_OFF + elif c.uuid == btle.AssignedNumbers.device_information: + string = repr(val) + else: + string = '' + else: + string = '' + print ("\t%04x: %-59s %-12s %s" % (h, c, props, string)) + + while True: + h += 1 + if h > s.hndEnd or (i < len(chars) - 1 and h >= chars[i + 1].getHandle() - 1): + break + try: + val = dev.readCharacteristic(h) + print ("\t%04x: <%s>" % + (h, binascii.b2a_hex(val).decode('utf-8'))) + except btle.BTLEException: + break + + +class ScanPrint(btle.DefaultDelegate): + + def __init__(self, opts): + btle.DefaultDelegate.__init__(self) + self.opts = opts + self.device_name = ATC_db_helper.get_table_value_from_field('atc_device_name', 'name') + if (self.device_name == None): + self.device_name = ' ' + self.address = ("a4:c1:38:" + self.device_name[4:6] + ":" + self.device_name[6:8] + ":" + self.device_name[8:]).lower() +# print(self.address) + + def handleDiscovery(self, dev, isNewDev, isNewData): + if isNewDev: + status = "new" + elif isNewData: + if self.opts.new: + return + status = "update" + else: + if not self.opts.all: + return + status = "old" + + if dev.rssi < self.opts.sensitivity: + return + + # filter desired device, addresses must match + if (dev.addr != self.address): + return + +# print (' Device (%s): %s (%s), %d dBm %s' % +# (status, +# ANSI_WHITE + dev.addr + ANSI_OFF, +# dev.addrType, +# dev.rssi, +# ('' if dev.connectable else '(not connectable)')) +# ) + device_name = ' ' + advertise_data = '' + for (sdid, desc, val) in dev.getScanData(): + if sdid in [8, 9]: +# print ('\t' + desc + ': \'' + ANSI_CYAN + val + ANSI_OFF + '\'') + device_name = val + else: +# print ('\t' + desc + ': <' + val + '>') + advertise_data = val + +# print("device name : " + device_name + ". data : " + advertise_data) + temperature = int.from_bytes(bytearray.fromhex(advertise_data[16:20]),byteorder='little',signed=True) / 100. + humidity = int.from_bytes(bytearray.fromhex(advertise_data[20:24]),byteorder='little',signed=False) / 100. + batteryVoltage = int.from_bytes(bytearray.fromhex(advertise_data[24:28]),byteorder='little',signed=False) / 1000. + batteryPercent = int.from_bytes(bytearray.fromhex(advertise_data[28:30]),byteorder='little',signed=False) + timestamp = ATC_db_helper.get_current_time() + # formatted_time = datetime.fromtimestamp(timestamp) + # syslog.syslog(syslog.LOG_INFO, f'Temperature: {temperature:.2f}. Humidity: {humidity:3.1f}. Battery voltage: {batteryVoltage:.2f}. Battery percent: {batteryPercent}. Timestamp: {formatted_time}') + ATC_db_helper.write_atc_data( temperature, humidity, batteryVoltage, batteryPercent, timestamp) + +# if not dev.scanData: +# print ('\t(no data)') +# print + +def job(): + parser = argparse.ArgumentParser() + parser.add_argument('-i', '--hci', action='store', type=int, default=0, + help='Interface number for scan') + parser.add_argument('-t', '--timeout', action='store', type=int, default=6, + help='Scan delay, 0 for continuous') + parser.add_argument('-s', '--sensitivity', action='store', type=int, default=-128, + help='dBm value for filtering far devices') + parser.add_argument('-d', '--discover', action='store_true', + help='Connect and discover service to scanned devices') + parser.add_argument('-a', '--all', action='store_true', + help='Display duplicate adv responses, by default show new + updated') + parser.add_argument('-n', '--new', action='store_true', + help='Display only new adv responses, by default show new + updated') + parser.add_argument('-v', '--verbose', action='store_true', + help='Increase output verbosity') + arg = parser.parse_args(sys.argv[1:]) + + btle.Debugging = arg.verbose + + try: + scanner = btle.Scanner(arg.hci).withDelegate(ScanPrint(arg)) + +# print (ANSI_RED + "Scanning for devices..." + ANSI_OFF) + devices = scanner.scan(arg.timeout) +# assert False, 'testing assertion' + + except Exception as exc: + error = traceback.format_exc() + syslog.syslog(syslog.LOG_ERR, error) + + if arg.discover: + print (ANSI_RED + "Discovering services..." + ANSI_OFF) + + for d in devices: + if not d.connectable or d.rssi < arg.sensitivity: + + continue + + print (" Connecting to", ANSI_WHITE + d.addr + ANSI_OFF + ":") + + dev = btle.Peripheral(d) + dump_services(dev) + dev.disconnect() + print + +# if __name__ == "__main__": +# main() + +def do_cancel_job(): +# print("sigterm or sigint received") + schedule.cancel_job(job) + syslog.syslog(syslog.LOG_INFO, "ATC_xxxxxx.py stopped") + sys.exit(0) + +syslog.syslog(syslog.LOG_INFO, "ATC_xxxxxx.py started") + +# now enable signal handler +signal.signal(signal.SIGTERM, signal_handler) +signal.signal(signal.SIGINT, signal_handler) +ATC_db_helper.empty_table('atc_data') # clear mi-data table + +schedule.every(2).seconds.do(job) + +while True: + schedule.run_pending() + time.sleep(1) + + diff --git a/opt/ATC_MiThermometer/pi-ager_atc_data_2023-08-27.dump.sql b/opt/ATC_MiThermometer/pi-ager_atc_data_2023-08-27.dump.sql new file mode 100644 index 000000000..2835ccb3d --- /dev/null +++ b/opt/ATC_MiThermometer/pi-ager_atc_data_2023-08-27.dump.sql @@ -0,0 +1,23 @@ +---- +-- phpLiteAdmin database dump (https://www.phpliteadmin.org/) +-- phpLiteAdmin version: 1.9.8.2 +-- Exported: 8:47pm on August 27, 2023 (CEST) +-- database file: ./config/pi-ager.sqlite3 +---- +BEGIN TRANSACTION; + +---- +-- Drop table for atc_data +---- +DROP TABLE IF EXISTS "atc_data"; + +---- +-- Table structure for atc_data +---- +CREATE TABLE 'atc_data' ('id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 'temperature' REAL, 'humidity' REAL, 'battvolt' REAL, 'battpercent' REAL, 'last_change' INTEGER); + +---- +-- Data dump for atc_data, a total of 1 rows +---- +INSERT INTO "atc_data" ("id","temperature","humidity","battvolt","battpercent","last_change") VALUES ('1','25.66','55.9','2.883','75.0','1693162020'); +COMMIT; diff --git a/opt/ATC_MiThermometer/pi-ager_atc_device_name_2023-08-27.dump.sql b/opt/ATC_MiThermometer/pi-ager_atc_device_name_2023-08-27.dump.sql new file mode 100644 index 000000000..0366a62d1 --- /dev/null +++ b/opt/ATC_MiThermometer/pi-ager_atc_device_name_2023-08-27.dump.sql @@ -0,0 +1,23 @@ +---- +-- phpLiteAdmin database dump (https://www.phpliteadmin.org/) +-- phpLiteAdmin version: 1.9.8.2 +-- Exported: 8:46pm on August 27, 2023 (CEST) +-- database file: ./config/pi-ager.sqlite3 +---- +BEGIN TRANSACTION; + +---- +-- Drop table for atc_device_name +---- +DROP TABLE IF EXISTS "atc_device_name"; + +---- +-- Table structure for atc_device_name +---- +CREATE TABLE 'atc_device_name' (id INTEGER PRIMARY KEY,'name' TEXT DEFAULT ''); + +---- +-- Data dump for atc_device_name, a total of 1 rows +---- +INSERT INTO "atc_device_name" ("id","name") VALUES ('1','ATC_C4C134'); +COMMIT; diff --git a/opt/MiTemperature2/MiCallback.sh b/opt/MiTemperature2/MiCallback.sh deleted file mode 100644 index fdf8f7be7..000000000 --- a/opt/MiTemperature2/MiCallback.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -sqlite3 /var/www/config/pi-ager.sqlite3 < 1 else _('day')) + period_hours_logstring="\n" + '.................................' + _('duration') + ": " + str(period_dictionary['hours']) + ' ' + (_('hours') if period_dictionary['hours'] > 1 else _('hour')) sensor_logstring = '.................................' + _('sensortype') + ": " + cl_fact_main_sensor_type().get_instance()._get_type_ui( ) pi_ager_database.write_settings(modus, period_dictionary['setpoint_temperature'], period_dictionary['setpoint_humidity'], period_dictionary['circulation_air_period'], period_dictionary['circulation_air_duration'], period_dictionary['exhaust_air_period'], period_dictionary['exhaust_air_duration']) - period_starttime_seconds = pi_ager_database.get_current_time() - period_first_day * day_in_seconds + period_starttime_seconds = pi_ager_database.get_current_time() - period_first_hour * hour_in_seconds pi_ager_database.write_current_value(pi_ager_names.agingtable_period_starttime_key, period_starttime_seconds) - period_endtime = datetime.datetime.now() + datetime.timedelta(days = period_dictionary['days'] - period_first_day) # days = parameter von datetime.timedelta + period_endtime = datetime.datetime.now() + datetime.timedelta(hours = period_dictionary['hours'] - period_first_hour) # hours = parameter von datetime.timedelta - logstring = _('values') + ': ' + operating_mode + setpoint_temperature_logstring + switch_on_cooling_compressor_logstring + switch_off_cooling_compressor_logstring + delay_cooling_compressor_logstring + "\n" + setpoint_humidity_logstring + switch_on_humidifier_logstring + switch_off_humidifier_logstring + delay_humidify_logstring + "\n" + circulation_air_period_logstring + circulation_air_duration_logstring + "\n" + exhaust_air_period_logstring + exhaust_air_duration_logstring + "\n" + period_days_logstring + "\n" + sensor_logstring + "\n" + logstring = _('values') + ': ' + operating_mode + setpoint_temperature_logstring + primary_hysteresis_logstring + secondary_hysteresis_logstring + delay_cooling_compressor_logstring + "\n" + setpoint_humidity_logstring + humidifier_hysteresis_logstring + dehumidifier_hysteresis_logstring + delay_humidify_logstring + "\n" + circulation_air_period_logstring + circulation_air_duration_logstring + "\n" + exhaust_air_period_logstring + exhaust_air_duration_logstring + "\n" + period_hours_logstring + "\n" + sensor_logstring + "\n" cl_fact_logger.get_instance().info(logstring) - def eval_final_time(self, rows, start_period, start_day): + def eval_final_time(self, rows, start_period, start_hour): """ - evaluate final time, when aging starts in rows[period] and with first_day in period + evaluate final time, when aging starts in rows[period] and with first_hour in period """ row_number = 0 # Setzt Variable row_number auf 0 - total_days = int(rows[int(start_period)]["days"]) - start_day # Setzt Variable duration auf 0 + total_hours = int(rows[int(start_period)]["hours"]) - start_hour # Setzt Variable duration auf 0 total_rows = len(rows) if total_rows > (start_period + 1): for var in list(range(int(start_period) + 1, int(total_rows))): - total_days += int(rows[var]["days"]) # errechnet die Gesamtdauer + total_hours += int(rows[var]["hours"]) # errechnet die Gesamtdauer - finaltime = datetime.datetime.now() + datetime.timedelta(days = total_days) # days = parameter von datetime.timedeltatotal_periods = row_number - 1 + finaltime = datetime.datetime.now() + datetime.timedelta(hours = total_hours) # hours = parameter von datetime.timedeltatotal_periods = row_number - 1 return finaltime @@ -202,17 +212,18 @@ def get_general_config_values(self): """ read some general config values from db: switch_on/off and delay for temperature and humidity control for log only """ - global switch_on_cooling_compressor - global switch_off_cooling_compressor - global switch_on_humidifier - global switch_off_humidifier global delay_humidify global delay_cooling_compressor + global cooling_hysteresis + global heating_hysteresis + global humidifier_hysteresis + global dehumidifier_hysteresis + + cooling_hysteresis = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.cooling_hysteresis_key) + heating_hysteresis = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.heating_hysteresis_key) + humidifier_hysteresis = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.humidifier_hysteresis_key) + dehumidifier_hysteresis = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.dehumidifier_hysteresis_key) - switch_on_cooling_compressor = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_cooling_compressor_key) - switch_off_cooling_compressor = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_off_cooling_compressor_key) - switch_on_humidifier = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_humidifier_key) - switch_off_humidifier = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_off_humidifier_key) delay_humidify = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.delay_humidify_key) delay_cooling_compressor = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.delay_cooler_key) @@ -224,7 +235,7 @@ def doAgingtableLoop(self): global period_starttime_seconds global period_endtime global duration_sleep - global day_in_seconds + global hour_in_seconds while True: time.sleep(1) @@ -236,11 +247,11 @@ def doAgingtableLoop(self): continue last_period = int(pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.agingtable_period_key)) # remember last period - last_period_day = int(pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.agingtable_period_day_key)) # remember last period_day + last_period_hour = int(pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.agingtable_period_hour_key)) # remember last period_hour manual_start_period = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.agingtable_startperiod_key)) - manual_start_day = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.agingtable_startday_key)) - pi_ager_database.update_value_in_table(pi_ager_names.config_settings_table, pi_ager_names.agingtable_startday_key, 1) + manual_start_hour = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.agingtable_starthour_key)) + pi_ager_database.update_value_in_table(pi_ager_names.config_settings_table, pi_ager_names.agingtable_starthour_key, 1) pi_ager_database.update_value_in_table(pi_ager_names.config_settings_table, pi_ager_names.agingtable_startperiod_key, 1) period_settings = {} @@ -255,9 +266,9 @@ def doAgingtableLoop(self): debug_modus = pi_ager_database.get_table_value(pi_ager_names.debug_table, pi_ager_names.loglevel_console_key) if debug_modus == 10: - day_in_seconds = pi_ager_database.get_table_value(pi_ager_names.debug_table, pi_ager_names.agingtable_days_in_seconds_debug_key) # zum testen Wert aus DB holen: ein Tag vergeht in einer Sekunde + hour_in_seconds = pi_ager_database.get_table_value(pi_ager_names.debug_table, pi_ager_names.agingtable_hours_in_seconds_debug_key) # zum testen Wert aus DB holen: eine Stunde vergeht in einer Sekunde else: - day_in_seconds = 86400 #Anzahl der Sek. in einem Tag + hour_in_seconds = 3600 #Anzahl der Sek. in einer Stunde # Hauptprogramm @@ -271,31 +282,31 @@ def doAgingtableLoop(self): dict_agingtable={} for row in rows: - total_duration += int(row["days"]) # errechnet die Gesamtdauer + total_duration += int(row["hours"]) # errechnet die Gesamtdauer dict_agingtable[row_number] = self.get_dictionary_out_of_sqliterow(row) row_number += 1 # Zeilenanzahl wird hochgezaehlt (fuer Dictionary Nummer und total_periods) total_periods = row_number - 1 - cl_fact_logger.get_instance().debug('total duration (days): ' + str(total_duration)) + cl_fact_logger.get_instance().debug('total duration (hours): ' + str(total_duration)) cl_fact_logger.get_instance().debug('total periods: ' + str(total_periods + 1)) # make shure not to start with a period out of range if (last_period > total_periods): last_period = 0 pi_ager_database.write_current_value(pi_ager_names.agingtable_period_key, last_period) - pi_ager_database.write_current_value(pi_ager_names.agingtable_period_day_key, 1) + pi_ager_database.write_current_value(pi_ager_names.agingtable_period_hour_key, 1) # how many days in last_period actual_dictionary = dict_agingtable[last_period] #ausgewaehlte periode aus dem Reifetabellendictionary auswaehlen - days_in_period = int(actual_dictionary['days']) - if (last_period_day > days_in_period): - last_period_day = days_in_period - pi_ager_database.write_current_value(pi_ager_names.agingtable_period_day_key, last_period_day) + hours_in_period = int(actual_dictionary['hours']) + if (last_period_hour > hours_in_period): + last_period_hour = hours_in_period + pi_ager_database.write_current_value(pi_ager_names.agingtable_period_hour_key, last_period_hour) period = last_period - start_day = last_period_day - cl_fact_logger.get_instance().debug('Last period: ' + str(period + 1) + '. Last start_day: ' + str(start_day)) + start_hour = last_period_hour + cl_fact_logger.get_instance().debug('Last period: ' + str(period + 1) + '. Last start_hour: ' + str(start_hour)) # Start der Reifetabelle ab bestimmter Zeit oder wenn Reifevorgang unterbrochen wurde continue_agingtable = False @@ -303,22 +314,22 @@ def doAgingtableLoop(self): # Start Reifetabelle vom Anfang begin_agingtable = False - if manual_start_day != 1 or manual_start_period != 1: # Wenn ueber das Frontend ein Starttag oder eine Startperiode eingetragen wurde + if manual_start_hour != 1 or manual_start_period != 1: # Wenn ueber das Frontend ein Startstunde oder eine Startperiode eingetragen wurde if (manual_start_period > (total_periods + 1)): manual_start_period = total_periods + 1 actual_dictionary = dict_agingtable[manual_start_period - 1] #ausgewaehlte periode aus dem Reifetabellendictionary auswaehlen - days_in_period = int(actual_dictionary['days']) - if (manual_start_day > days_in_period): - manual_start_day = days_in_period - duration_sleep = self.get_duration_sleep(days_in_period) #Laufzeit der Periode auslesen - period_starttime_seconds = pi_ager_database.get_current_time() - (manual_start_day - 1) * day_in_seconds # eigentlicher Startzeitpunkt der Periode zur Berechnung der Sleeptime + hours_in_period = int(actual_dictionary['hours']) + if (manual_start_hour > hours_in_period): + manual_start_hour = hours_in_period + duration_sleep = self.get_duration_sleep(hours_in_period) #Laufzeit der Periode auslesen + period_starttime_seconds = pi_ager_database.get_current_time() - (manual_start_hour - 1) * hour_in_seconds # eigentlicher Startzeitpunkt der Periode zur Berechnung der Sleeptime period = manual_start_period - 1 - start_day = manual_start_day - cl_fact_logger.get_instance().debug('Manual period: ' + str(period) + '. Manual start_day: ' + str(start_day)) + start_hour = manual_start_hour + cl_fact_logger.get_instance().debug('Manual period: ' + str(period) + '. Manual start_hour: ' + str(start_hour)) continue_agingtable = True # Boolean fuer das erkennen der manuellen Startzeit # Wenn period == 0 und start_day == 1 wird die Reifetabelle neu gestartet, ansonsten an der aktuellen period fortgesetzt - elif period == 0 and start_day == 1: + elif period == 0 and start_hour == 1: period_starttime_seconds = 0 duration_sleep = 0 actual_dictionary = None # setzt aktuelles Dictionary zurueck @@ -334,13 +345,13 @@ def doAgingtableLoop(self): # status_agingtable = 0 else: # setze agingtable fort nach Unterbrechung. Wir machen keine Toleranzprüfung mehr. (Sensorwerte sind im Toleranzbereich, Reifetabelle kann normal fortgesetzt werden) - duration_sleep = self.get_duration_sleep(days_in_period) # Laufzeit der Periode auslesen - period_starttime_seconds = pi_ager_database.get_current_time() - (start_day - 1) * day_in_seconds # eigentlicher Startzeitpunkt der Periode zur Berechnung der Sleeptime + duration_sleep = self.get_duration_sleep(hours_in_period) # Laufzeit der Periode auslesen + period_starttime_seconds = pi_ager_database.get_current_time() - (start_hour - 1) * hour_in_seconds # eigentlicher Startzeitpunkt der Periode zur Berechnung der Sleeptime continue_agingtable = True pi_ager_database.write_current_value(pi_ager_names.agingtable_period_key, period) - pi_ager_database.write_current_value(pi_ager_names.agingtable_period_day_key, start_day) #Tag der Periode in DB schreiben - old_current_day = start_day + pi_ager_database.write_current_value(pi_ager_names.agingtable_period_hour_key, start_hour) #Stunde der Periode in DB schreiben + old_current_hour = start_hour while True: time.sleep(1) @@ -350,7 +361,7 @@ def doAgingtableLoop(self): status_agingtable = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.status_agingtable_key) if (status_agingtable == 0): # user turned off aging table pi_ager_database.write_current_value(pi_ager_names.agingtable_period_key, 0) - pi_ager_database.write_current_value(pi_ager_names.agingtable_period_day_key, 1) + pi_ager_database.write_current_value(pi_ager_names.agingtable_period_hour_key, 1) break current_time = pi_ager_database.get_current_time() @@ -365,7 +376,7 @@ def doAgingtableLoop(self): # aging table finished pi_ager_database.write_stop_in_database(pi_ager_names.status_agingtable_key) pi_ager_database.write_current_value(pi_ager_names.agingtable_period_key, 0) - pi_ager_database.write_current_value(pi_ager_names.agingtable_period_day_key, 1) + pi_ager_database.write_current_value(pi_ager_names.agingtable_period_hour_key, 1) break pi_ager_database.write_current_value(pi_ager_names.agingtable_period_key, period) @@ -373,22 +384,22 @@ def doAgingtableLoop(self): actual_dictionary = dict_agingtable[period] if continue_agingtable: # if start with period within agingtable - old_current_day = start_day - pi_ager_database.write_current_value(pi_ager_names.agingtable_period_day_key, start_day) #Tag der Periode in DB schreiben + old_current_hour = start_hour + pi_ager_database.write_current_value(pi_ager_names.agingtable_period_hour_key, start_hour) #Stunde der Periode in DB schreiben logstring = _('start with period ') + str(int(period + 1)) + ' ' + _('of') + ' ' + str(int(total_periods + 1)) cl_fact_logger.get_instance().info(logstring) - final_time = self.eval_final_time(rows, period, start_day - 1) - self.read_dictionary_write_settings(actual_dictionary, start_day - 1) + finaltime = self.eval_final_time(rows, period, start_hour - 1) + self.read_dictionary_write_settings(actual_dictionary, start_hour - 1) logstring = _('next change of values') + ': ' + period_endtime.strftime('%d.%m.%Y %H:%M') cl_fact_logger.get_instance().info(logstring) - logstring = _('end of program') + ': ' + final_time.strftime('%d.%m.%Y %H:%M') + logstring = _('end of program') + ': ' + finaltime.strftime('%d.%m.%Y %H:%M') cl_fact_logger.get_instance().info(logstring) continue_agingtable = False elif begin_agingtable: # if start with first period logstring = _('start values period 1 of') + ' ' + str(int(total_periods + 1)) cl_fact_logger.get_instance().info(logstring) - finaltime = datetime.datetime.now() + datetime.timedelta(days = total_duration) # days = parameter von datetime.timedelta + finaltime = datetime.datetime.now() + datetime.timedelta(hours = total_duration) # hours = parameter von datetime.timedelta self.read_dictionary_write_settings(actual_dictionary) logstring = _('next change of values') + ': ' + period_endtime.strftime('%d.%m.%Y %H:%M') cl_fact_logger.get_instance().info(logstring) @@ -404,8 +415,9 @@ def doAgingtableLoop(self): cl_fact_logger.get_instance().info(logstring) if finaltime == None: - period_starttime = datetime.datetime.fromtimestamp(period_starttime_seconds) - finaltime = period_starttime + datetime.timedelta(days = total_duration) + finaltime = self.eval_final_time(rows, period, start_hour - 1) + # period_starttime = datetime.datetime.fromtimestamp(period_starttime_seconds) + # finaltime = period_starttime + datetime.timedelta(days = total_duration) logstring = _('end of program') + ': ' + finaltime.strftime('%d.%m.%Y %H:%M') cl_fact_logger.get_instance().info(logstring) @@ -421,11 +433,11 @@ def doAgingtableLoop(self): # remaining_days = (period_starttime_seconds + duration_sleep - current_time - 1) // day_in_seconds # current_day = int (actual_dictionary['days']) - remaining_days # aktueller Tag ist Tage aus Reifetabelle - die restlichen Tage - current_day = (current_time - period_starttime_seconds) // day_in_seconds + 1 - if (current_day != old_current_day): - pi_ager_database.write_current_value(pi_ager_names.agingtable_period_day_key, current_day) # Tag der Periode in DB schreiben - old_current_day = current_day - cl_fact_logger.get_instance().debug('New current day : ' + str(current_day)) + current_hour = (current_time - period_starttime_seconds) // hour_in_seconds + 1 + if (current_hour != old_current_hour): + pi_ager_database.write_current_value(pi_ager_names.agingtable_period_hour_key, current_hour) # Stunde der Periode in DB schreiben + old_current_hour = current_hour + cl_fact_logger.get_instance().debug('New current hour : ' + str(current_hour)) # pi_ager_database.write_stop_in_database(pi_ager_names.status_agingtable_key) # pi_ager_database.write_current_value(pi_ager_names.agingtable_period_key, 0) diff --git a/opt/pi-ager/pi_ager_cl_mqtt.py b/opt/pi-ager/pi_ager_cl_mqtt.py new file mode 100644 index 000000000..4c54fc7d2 --- /dev/null +++ b/opt/pi-ager/pi_ager_cl_mqtt.py @@ -0,0 +1,208 @@ +#!/usr/bin/python3 +""" + thread for MQTT client +""" +import pi_ager_names +import pi_ager_gpio_config +import globals +if __name__ == '__main__': + # init global threading.lock + globals.init() + import RPi.GPIO as gpio + gpio.setwarnings(False) + gpio.setmode(pi_ager_gpio_config.board_mode) + gpio.setup(pi_ager_gpio_config.gpio_power_monitor, gpio.IN ) + gpio.setup(pi_ager_gpio_config.gpio_ups_bat_low, gpio.IN ) + gpio.setup(pi_ager_gpio_config.gpio_switch, gpio.IN ) # manueller Schalter setzen + + import gettext + _ = gettext.gettext + +import pi_ager_database +from abc import ABC +import time +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +from main.pi_ager_cl_logger import cl_fact_logger +import paho.mqtt.client as mqtt +import socket +import threading + + +class cl_mqtt_thread( threading.Thread ): + + def __init__( self ): + super().__init__() + self.stop_received = False + self.client = None + self.topic = "/status" + + def get_current_values(self): # get all current values from db + current_value_rows = pi_ager_database.get_current(pi_ager_names.current_values_table, True) + current_values = {} + for current_row in current_value_rows: + current_values[current_row[pi_ager_names.key_field]] = current_row[pi_ager_names.value_field] + return current_values + + def run(self): + cl_fact_logger.get_instance().info(_('Start MQTT loop at') + ' ' + time.strftime('%H:%M:%S', time.localtime())) + self.client = mqtt.Client() + + while not self.stop_received and threading.main_thread().is_alive(): + config_mqtt = pi_ager_database.get_table_row(pi_ager_names.config_mqtt_table, 1) + + broker = config_mqtt[pi_ager_names.broker_address_field] + port = config_mqtt[pi_ager_names.port_field] + mqtt_active = config_mqtt[pi_ager_names.mqtt_active_field] + + if (mqtt_active == 0 or not broker or not port): + time.sleep(1) + continue + + username = config_mqtt[pi_ager_names.username_field] + password = config_mqtt[pi_ager_names.password_field] + + try: + # try to connect to broker + # print("Connecting") + self.client.username_pw_set(username, password) + self.client.connect(broker, port) + # print("Connected") + + except Exception as e: + # if __name__ == '__main__': + # cl_fact_logger.get_instance().info('MQTT thread in exception ' + str(e)) + # else: + # cl_fact_logic_messenger().get_instance().handle_exception(cx_error) + + # if self.stop_received == True: + # cl_fact_logger.get_instance().info(_('MQTT loop stopped at') + ' ' + time.strftime('%H:%M:%S', time.localtime())) + # return # should stop thread + time.sleep(1) + continue + + # print("Start publish") + try: + hostname = socket.gethostname() + ups_bat_low_temp = pi_ager_gpio_config.check_ups_bat_low() + UPS_battery = ('ok' if ups_bat_low_temp else 'low') + + power_monitor_state = pi_ager_gpio_config.check_power_monitor() + power_monitor = ('powergood' if power_monitor_state else 'powerfail') + + pi_switch_temp = pi_ager_gpio_config.check_switch() + pi_switch = ('off' if pi_switch_temp else 'on') + + current_values = self.get_current_values() + + self.client.loop_start() + self.client.publish(hostname + self.topic + "/" + pi_ager_names.status_pi_ager_key , str(int(current_values[pi_ager_names.status_pi_ager_key]))) + if (int(current_values[pi_ager_names.status_pi_ager_key]) == 1): + self.client.publish(hostname + self.topic + "/" + pi_ager_names.temperature_avg_key , str(current_values[pi_ager_names.temperature_avg_key])) + self.client.publish(hostname + self.topic + "/" + pi_ager_names.humidity_avg_key , str(current_values[pi_ager_names.humidity_avg_key])) + self.client.publish(hostname + self.topic + "/" + pi_ager_names.humidity_abs_avg_key , str(current_values[pi_ager_names.humidity_abs_avg_key])) + + tmp = current_values[pi_ager_names.second_sensor_temperature_key] + if tmp != None: + self.client.publish(hostname + self.topic + "/" + pi_ager_names.second_sensor_temperature_key , str(tmp)) + tmp = current_values[pi_ager_names.second_sensor_humidity_key] + if tmp != None: + self.client.publish(hostname + self.topic + "/" + pi_ager_names.second_sensor_humidity_key , str(tmp)) + tmp = current_values[pi_ager_names.second_sensor_humidity_abs_key] + if tmp != None: + self.client.publish(hostname + self.topic + "/" + pi_ager_names.second_sensor_humidity_abs_key , str(tmp)) + + tmp = current_values[pi_ager_names.temperature_meat1_key] + if tmp != None: + self.client.publish(hostname + self.topic + "/" + pi_ager_names.temperature_meat1_key , str(tmp)) + tmp = current_values[pi_ager_names.temperature_meat2_key] + if tmp != None: + self.client.publish(hostname + self.topic + "/" + pi_ager_names.temperature_meat2_key , str(tmp)) + tmp = current_values[pi_ager_names.temperature_meat3_key] + if tmp != None: + self.client.publish(hostname + self.topic + "/" + pi_ager_names.temperature_meat3_key , str(tmp)) + tmp = current_values[pi_ager_names.temperature_meat4_key] + if tmp != None: + self.client.publish(hostname + self.topic + "/" + pi_ager_names.temperature_meat4_key , str(tmp)) + + self.client.publish(hostname + self.topic + "/" + pi_ager_names.status_heater_key , str(int(current_values[pi_ager_names.status_heater_key]))) + self.client.publish(hostname + self.topic + "/" + pi_ager_names.status_cooling_compressor_key , str(int(current_values[pi_ager_names.status_cooling_compressor_key]))) + self.client.publish(hostname + self.topic + "/" + pi_ager_names.status_humidifier_key , str(int(current_values[pi_ager_names.status_humidifier_key]))) + self.client.publish(hostname + self.topic + "/" + pi_ager_names.status_exhaust_air_key , str(int(current_values[pi_ager_names.status_exhaust_air_key]))) + self.client.publish(hostname + self.topic + "/" + pi_ager_names.status_circulating_air_key , str(int(current_values[pi_ager_names.status_circulating_air_key]))) + self.client.publish(hostname + self.topic + "/" + pi_ager_names.status_uv_key , str(int(current_values[pi_ager_names.status_uv_key]))) + self.client.publish(hostname + self.topic + "/" + pi_ager_names.status_light_key , str(int(current_values[pi_ager_names.status_light_key]))) + self.client.publish(hostname + self.topic + "/" + pi_ager_names.status_dehumidifier_key , str(int(current_values[pi_ager_names.status_dehumidifier_key]))) + + if (int(current_values[pi_ager_names.status_scale1_key]) == 0): + pass # self.client.publish(hostname + self.topic + "/" + pi_ager_names.scale1_key , "None") + else: + self.client.publish(hostname + self.topic + "/" + pi_ager_names.scale1_key , str(current_values[pi_ager_names.scale1_key])) + + if (int(current_values[pi_ager_names.status_scale2_key]) == 0): + pass # self.client.publish(hostname + self.topic + "/" + pi_ager_names.scale2_key , "None") + else: + self.client.publish(hostname + self.topic + "/" + pi_ager_names.scale2_key , str(current_values[pi_ager_names.scale2_key])) + + self.client.publish(hostname + self.topic + "/" + 'pi_switch_state', pi_switch) + self.client.publish(hostname + self.topic + "/" + 'power_monitor_state', power_monitor) + self.client.publish(hostname + self.topic + "/" + 'UPS_battery_state', UPS_battery) + + if (not globals.mqtt_msg_queue.empty()): + self.client.publish(hostname + self.topic + "/" + 'event', globals.mqtt_msg_queue.get()) + + self.client.loop_stop() + self.client.disconnect() + except Exception as e: + cl_fact_logger.get_instance().info('MQTT thread in exception ' + str(e)) + + time.sleep(5) + + cl_fact_logger.get_instance().info(_('MQTT loop stopped at') + ' ' + time.strftime('%H:%M:%S', time.localtime())) + + +class cl_fact_mqtt(ABC): + __o_instance = None + + @classmethod + def set_instance(self, i_instance): + """ + Factory method to set the mqtt instance + """ + cl_fact_mqtt.__o_instance = i_instance + + @classmethod + def get_instance(self): + """ + Factory method to get the mqtt instance + """ + if cl_fact_mqtt.__o_instance is not None: + return(cl_fact_mqtt.__o_instance) + cl_fact_mqtt.__o_instance = cl_mqtt_thread() + return(cl_fact_mqtt.__o_instance) + + def __init__(self): + """ + Constructor nextion factory + """ + pass + + +def main(): + mqtt_thread = cl_fact_mqtt().get_instance() + mqtt_thread.start() + + try: + while True: + time.sleep(1) + + except KeyboardInterrupt: + print("Ctrl-c received! Sending Stop to thread...") + mqtt_thread.stop_received = True + + mqtt_thread.join() + print('thread finished.') + + +if __name__ == '__main__': + main() + \ No newline at end of file diff --git a/opt/pi-ager/pi_ager_cl_nextion.py b/opt/pi-ager/pi_ager_cl_nextion.py index 48c1ef8f4..81537024a 100644 --- a/opt/pi-ager/pi_ager_cl_nextion.py +++ b/opt/pi-ager/pi_ager_cl_nextion.py @@ -102,7 +102,7 @@ async def update_light_val(self): await self.client.set('btn_light.pic', 41) async def turn_off_light(self): - cl_fact_logger.get_instance().info('Light turned off after 10 minutes timeout') + cl_fact_logger.get_instance().info(_('Light turned off after 10 minutes timeout')) # gpio.output(pi_ager_gpio_config.gpio_light, True) globals.requested_state_light = pi_ager_names.relay_off globals.hands_off_light_switch = False @@ -117,7 +117,7 @@ async def turn_off_light(self): async def control_light_status(self): #light_status = await self.client.get('values.status_light.val') if self.light_status == True: - cl_fact_logger.get_instance().info('Light turned off') + cl_fact_logger.get_instance().info(_('Light turned off')) self.light_status = False # turn off if self.current_theme == 'fridge': await self.client.set('btn_light.pic', 12) @@ -131,7 +131,7 @@ async def control_light_status(self): # pi_ager_database.update_value_in_table(pi_ager_names.current_values_table, pi_ager_names.status_light_key, 0) else: - cl_fact_logger.get_instance().info('Light turned on') + cl_fact_logger.get_instance().info(_('Light turned on')) self.light_status = True # turn on if self.current_theme == 'fridge': await self.client.set('btn_light.pic', 13) @@ -201,7 +201,7 @@ async def wakeup_waiter(self, event): # process touch screen wakeup event self.wakeup_event.clear() cl_fact_logger.get_instance().debug('wakeup event processed') except Exception as e: - cl_fact_logger.get_instance().error('wakeup_waiter stopped ' + str(e)) + cl_fact_logger.get_instance().error(_('wakeup_waiter stopped ') + str(e)) pass async def button_waiter(self, event): # process touch screen button events @@ -220,33 +220,36 @@ async def button_waiter(self, event): # process touch screen button events # await self.client.set('sleep', 0) await self.client.command('page 1') self.current_page_id = 1 - elif self.data.page_id == 8: + elif self.data.page_id == 8: # boot_steak await self.client.command('page 9') - self.current_page_id = 9 - elif self.data.page_id == 1 and self.data.component_id == 8: + self.current_page_id = 9 # main_steak + elif self.data.page_id == 1 and self.data.component_id == 8: # main_fridge, btn_light await self.control_light_status() - elif self.data.page_id == 1 and self.data.component_id == 7: + elif self.data.page_id == 1 and self.data.component_id == 7: # main_fridge, btn_menu await self.client.command('page 2') self.current_page_id = 2 - elif self.data.page_id == 2 and self.data.component_id == 6: + elif self.data.page_id == 1 and self.data.component_id == 9: # main_fridge, btn_wifi + await self.client.command('page 6') + self.current_page_id = 6 # info_fridge + elif self.data.page_id == 2 and self.data.component_id == 6: # menu_fridge, btn_light await self.control_light_status() - elif self.data.page_id == 2 and self.data.component_id == 1: + elif self.data.page_id == 2 and self.data.component_id == 1: # menu_fridge, btn_home await self.client.command('page 1') self.current_page_id = 1 - elif self.data.page_id == 2 and self.data.component_id == 2: + elif self.data.page_id == 2 and self.data.component_id == 2: # menu_fridge, btn_states await self.client.command('page 3') self.current_page_id = 3 - elif self.data.page_id == 2 and self.data.component_id == 3: + elif self.data.page_id == 2 and self.data.component_id == 3: # menu_fridge, btn_values await self.client.command('page 4') self.current_page_id = 4 - elif self.data.page_id == 2 and self.data.component_id == 4: + elif self.data.page_id == 2 and self.data.component_id == 4: # menu_fridge, btn_settings await self.client.command('page 7') self.current_page_id = 7 - elif self.data.page_id == 2 and self.data.component_id == 5: + elif self.data.page_id == 2 and self.data.component_id == 5: # menu_fridge, btn_info await self.init_info_page_values() await self.client.command('page 6') self.current_page_id = 6 - elif self.data.page_id == 2 and self.data.component_id == 7: + elif self.data.page_id == 2 and self.data.component_id == 7: # menu_fridge, btn_themes if (self.current_theme == 'steak'): self.current_theme = 'fridge' await self.client.command('page 2') @@ -255,59 +258,71 @@ async def button_waiter(self, event): # process touch screen button events self.current_theme = 'steak' await self.client.command('page 10') self.current_page_id = 10 - elif self.data.page_id == 2 and self.data.component_id == 9: + elif self.data.page_id == 2 and self.data.component_id == 8: # menu_fridge, btn_control await self.client.command('page 17') self.current_page_id = 17 await self.init_page_17_19() - elif self.data.page_id == 3 and self.data.component_id == 1: + elif self.data.page_id == 2 and self.data.component_id == 9: # menu_fridge, btn_wifi + await self.client.command('page 6') + self.current_page_id = 6 + elif self.data.page_id == 3 and self.data.component_id == 1: # states_fridge, btn_light await self.control_light_status() - elif self.data.page_id == 3 and self.data.component_id == 10: + elif self.data.page_id == 3 and self.data.component_id == 10: # states_fridge, btn_menu await self.client.command('page 2') self.current_page_id = 2 - elif self.data.page_id == 3 and self.data.component_id == 11: + elif self.data.page_id == 3 and self.data.component_id == 11: # states_fridge, btn_home await self.client.command('page 1') - self.current_page_id = 1 - elif self.data.page_id == 4 and self.data.component_id == 1: + self.current_page_id = 1 + elif self.data.page_id == 3 and self.data.component_id == 12: # states_fridge, btn_wifi + await self.client.command('page 6') + self.current_page_id = 6 + elif self.data.page_id == 4 and self.data.component_id == 1: # values_fridge, btn_light await self.control_light_status() - elif self.data.page_id == 4 and self.data.component_id == 2: + elif self.data.page_id == 4 and self.data.component_id == 2: # values_fridge, btn_menu await self.client.command('page 2') self.current_page_id = 2 - elif self.data.page_id == 4 and self.data.component_id == 11: + elif self.data.page_id == 4 and self.data.component_id == 11: # values_fridge, btn_home await self.client.command('page 1') self.current_page_id = 1 - elif self.data.page_id == 6 and self.data.component_id == 1: + elif self.data.page_id == 4 and self.data.component_id == 12: # values_fridge, btn_wifi + await self.client.command('page 6') + self.current_page_id = 6 + elif self.data.page_id == 6 and self.data.component_id == 1: # info_fridge, btn_light await self.control_light_status() - elif self.data.page_id == 6 and self.data.component_id == 2: + elif self.data.page_id == 6 and self.data.component_id == 2: # info_fridge, btn_menu await self.client.command('page 2') self.current_page_id = 2 - elif self.data.page_id == 6 and self.data.component_id == 7: + elif self.data.page_id == 6 and self.data.component_id == 7: # info_fridge, btn_home await self.client.command('page 1') self.current_page_id = 1 - elif self.data.page_id == 7 and self.data.component_id == 1: + elif self.data.page_id == 7 and self.data.component_id == 1: # setting_fridge, btn_light await self.control_light_status() - elif self.data.page_id == 7 and self.data.component_id == 2: + elif self.data.page_id == 7 and self.data.component_id == 2: # setting_fridge, btn_menu await self.client.command('page 2') self.current_page_id = 2 - elif self.data.page_id == 7 and self.data.component_id == 7: + elif self.data.page_id == 7 and self.data.component_id == 7: # setting_fridge, btn_home await self.client.command('page 1') self.current_page_id = 1 - elif self.data.page_id == 9 and self.data.component_id == 7: + elif self.data.page_id == 7 and self.data.component_id == 12: # states_fridge, btn_wifi + await self.client.command('page 6') + self.current_page_id = 6 + elif self.data.page_id == 9 and self.data.component_id == 7: # menn_steak, btn_menu await self.client.command('page 10') self.current_page_id = 10 - elif self.data.page_id == 9 and self.data.component_id == 8: + elif self.data.page_id == 9 and self.data.component_id == 8: # main_steak, btn_light await self.control_light_status() - elif self.data.page_id == 10 and self.data.component_id == 6: + elif self.data.page_id == 9 and self.data.component_id == 18: # main_steak, btn_wifi + await self.client.command('page 14') + self.current_page_id = 14 + elif self.data.page_id == 10 and self.data.component_id == 6: # menu_steak, btn_light await self.control_light_status() - elif self.data.page_id == 10 and self.data.component_id == 1: # goto main_steak + elif self.data.page_id == 10 and self.data.component_id == 1: # menu_steak, btn_home, goto main_steak await self.client.command('page 9') self.current_page_id = 9 - elif self.data.page_id == 10 and self.data.component_id == 2: # goto values_steak + elif self.data.page_id == 10 and self.data.component_id == 2: # menu_steak, btn_values, goto values_steak await self.client.command('page 12') self.current_page_id = 12 - #elif self.data.page_id == 10 and self.data.component_id == 2: - # await self.client.command('page 11') - # self.current_page_id = 11 - elif self.data.page_id == 10 and self.data.component_id == 5: # goto menu_steak or menu_fridge + elif self.data.page_id == 10 and self.data.component_id == 5: # menu_steak, btn_themes, goto menu_steak or menu_fridge if (self.current_theme == 'steak'): self.current_theme = 'fridge' await self.client.command('page 2') @@ -316,75 +331,85 @@ async def button_waiter(self, event): # process touch screen button events self.current_theme = 'steak' await self.client.command('page 10') self.current_page_id = 10 - elif self.data.page_id == 10 and self.data.component_id == 3: # goto setting_steak + elif self.data.page_id == 10 and self.data.component_id == 3: # menu_steak, btn_settings, goto setting_steak await self.client.command('page 15') self.current_page_id = 15 - elif self.data.page_id == 10 and self.data.component_id == 4: # goto info_steak + elif self.data.page_id == 10 and self.data.component_id == 4: # menu_steak, btn_info, goto info_steak await self.init_info_page_values() await self.client.command('page 14') self.current_page_id = 14 - elif self.data.page_id == 10 and self.data.component_id == 8: # goto control_steak + elif self.data.page_id == 10 and self.data.component_id == 7: # menu_steak, btn_control, goto control_steak await self.client.command('page 19') self.current_page_id = 19 - await self.init_page_17_19() -# elif self.data.page_id == 11 and self.data.component_id == 18: -# await self.client.command('page 9') -# self.current_page_id = 9 -# elif self.data.page_id == 11 and self.data.component_id == 9: -# await self.control_light_status() - elif self.data.page_id == 12 and self.data.component_id == 1: + await self.init_page_17_19() + elif self.data.page_id == 10 and self.data.component_id == 8: # menu_steak, btn_wifi + await self.client.command('page 14') + self.current_page_id = 14 + elif self.data.page_id == 12 and self.data.component_id == 1: # values_steak, btn_menu await self.client.command('page 10') self.current_page_id = 10 - elif self.data.page_id == 12 and self.data.component_id == 10: + elif self.data.page_id == 12 and self.data.component_id == 10: # values_steak, btn_home await self.client.command('page 9') self.current_page_id = 9 - elif self.data.page_id == 12 and self.data.component_id == 11: - await self.control_light_status() - elif self.data.page_id == 14 and self.data.component_id == 1: + elif self.data.page_id == 12 and self.data.component_id == 11: # values_steak, btn_light + await self.control_light_status() + elif self.data.page_id == 12 and self.data.component_id == 12: # menu_steak, btn_wifi + await self.client.command('page 14') + self.current_page_id = 14 + elif self.data.page_id == 14 and self.data.component_id == 1: # info_steak, btn_menu await self.client.command('page 10') self.current_page_id = 10 - elif self.data.page_id == 14 and self.data.component_id == 6: + elif self.data.page_id == 14 and self.data.component_id == 6: # info_steak, btn_home await self.client.command('page 9') self.current_page_id = 9 - elif self.data.page_id == 14 and self.data.component_id == 7: - await self.control_light_status() - elif self.data.page_id == 15 and self.data.component_id == 7: + elif self.data.page_id == 14 and self.data.component_id == 7: # info_steak, btn_light + await self.control_light_status() + elif self.data.page_id == 15 and self.data.component_id == 7: # settings_steak, btn_menu await self.client.command('page 10') - self.current_page_id = 10 - elif self.data.page_id == 15 and self.data.component_id == 5: + self.current_page_id = 10 + elif self.data.page_id == 15 and self.data.component_id == 5: # settings_steak, btn_home await self.client.command('page 9') self.current_page_id = 9 - elif self.data.page_id == 15 and self.data.component_id == 6: - await self.control_light_status() - elif self.data.page_id == 17 and self.data.component_id == 3: # button menu + elif self.data.page_id == 15 and self.data.component_id == 6: # settings_steak, btn_light + await self.control_light_status() + elif self.data.page_id == 15 and self.data.component_id == 12: # settings_steak, btn_wifi + await self.client.command('page 14') + self.current_page_id = 14 + elif self.data.page_id == 17 and self.data.component_id == 3: # control_fridge, btn_menu await self.client.command('page 2') self.current_page_id = 2 - elif self.data.page_id == 17 and self.data.component_id == 4: # button home + elif self.data.page_id == 17 and self.data.component_id == 4: # control_fridge, btn_home await self.client.command('page 1') self.current_page_id = 1 - elif self.data.page_id == 17 and self.data.component_id == 2: # button light + elif self.data.page_id == 17 and self.data.component_id == 2: # control_fridge, btn_light await self.control_light_status() - elif self.data.page_id == 17 and self.data.component_id == 6: # button pi-ager start/stop + elif self.data.page_id == 17 and self.data.component_id == 5: # control_fridge, btn_piager, start/stop await self.control_piager_start_stop() - elif self.data.page_id == 17 and self.data.component_id == 9: # button save new Temp/Hum. values + elif self.data.page_id == 17 and self.data.component_id == 9: # control_fridge, btn_ok, button save new Temp/Hum. values await self.save_page_17_19_values() - elif self.data.page_id == 19 and self.data.component_id == 2: # button menu + elif self.data.page_id == 17 and self.data.component_id == 10: # control_fridge, btn_wifi + await self.client.command('page 6') + self.current_page_id = 6 + elif self.data.page_id == 19 and self.data.component_id == 2: # control_steak, btn_menu await self.client.command('page 10') self.current_page_id = 10 - elif self.data.page_id == 19 and self.data.component_id == 3: # button home + elif self.data.page_id == 19 and self.data.component_id == 3: # control_steak, btn_home await self.client.command('page 9') self.current_page_id = 9 - elif self.data.page_id == 19 and self.data.component_id == 4: # button light + elif self.data.page_id == 19 and self.data.component_id == 4: # control_steak, btn_light await self.control_light_status() - elif self.data.page_id == 19 and self.data.component_id == 9: # button pi-ager start/stop + elif self.data.page_id == 19 and self.data.component_id == 8: # control_steak, btn_piager, pi-ager start/stop await self.control_piager_start_stop() - elif self.data.page_id == 19 and self.data.component_id == 1: # button save new Temp/Hum. values + elif self.data.page_id == 19 and self.data.component_id == 1: # control_steak, btn_ok, save new Temp/Hum. values await self.save_page_17_19_values() - + elif self.data.page_id == 19 and self.data.component_id == 9: # control_steak, btn_wifi + await self.client.command('page 14') + self.current_page_id = 14 + self.button_event.clear() cl_fact_logger.get_instance().debug('button pressed processed') except Exception as e: - cl_fact_logger.get_instance().error('button_waiter stopped ' + str(e)) + cl_fact_logger.get_instance().error(_('button_waiter stopped ') + str(e)) pass def get_pi_model(self): @@ -402,10 +427,22 @@ def get_wifi_ssid(self): if output == '': return '' else: - return output.split('"')[1] + return (output.split('"')[1]).strip() except Exception as e: return '' - + + def get_ip_address(self): + try: + process = subprocess.run(['hostname', '-I'], check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + ip_addresses = (process.stdout).rstrip() + ip_address_list = ip_addresses.split() + if len(ip_address_list) == 0: + return '' + else: + return ip_address_list[0] + except Exception as e: + return '' + async def init_info_page_values(self): version = pi_ager_database.get_table_value(pi_ager_names.system_table, pi_ager_names.pi_ager_version_key ) display_type = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.tft_display_type_key ) @@ -425,8 +462,11 @@ async def init_info_page_values(self): # print('pi model: ' + model) await self.client.set('values.pi_model.txt', model) - wifi_ssid = self.get_wifi_ssid() - await self.client.set('values.wifi_conn.txt', wifi_ssid) +# wifi_ssid = self.get_wifi_ssid() +# await self.client.set('txt_wifi_conn.txt', wifi_ssid) + +# ip_address = self.get_ip_address() +# await self.client.set('txt_ip_address.txt', ip_address) await self.client.set('values.status_light.val', 0) @@ -442,10 +482,10 @@ async def init_display_values(self): def db_get_base_values(self): status_piager = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.status_pi_ager_key ) - temp_ist = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_temperature_key) - humidity_ist = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_humidity_key) - dewpoint_ist = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_dewpoint_key) - humabs = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_humidity_abs_key) + temp_ist = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.temperature_avg_key) + humidity_ist = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.humidity_avg_key) +# dewpoint_ist = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_dewpoint_key) + humabs = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.humidity_abs_avg_key) temp_soll = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.setpoint_temperature_key) humitidy_soll = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.setpoint_humidity_key) @@ -453,7 +493,7 @@ def db_get_base_values(self): values['status_piager'] = status_piager values['temp_ist'] = temp_ist values['humidity_ist'] = humidity_ist - values['dewpoint_ist'] = dewpoint_ist +# values['dewpoint_ist'] = dewpoint_ist values['humabs'] = humabs values['temp_soll'] = temp_soll values['humitidy_soll'] = humitidy_soll @@ -565,6 +605,13 @@ async def update_base_values(self): await self.client.set('txt_humid.txt', "%.1f" % (values['humidity_ist'])) await self.client.set('txt_humabs.txt', "%.1f" % (values['humabs'])) + async def update_info_values(self): + wifi_ssid = self.get_wifi_ssid() + await self.client.set('txt_wifi_conn.txt', wifi_ssid) + + ip_address = self.get_ip_address() + await self.client.set('txt_ip_address.txt', ip_address) + async def update_extended_values(self): values = self.db_get_extended_values() if values['status_piager'] == 0: @@ -623,14 +670,14 @@ async def update_page9_values(self): status_piager = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.status_pi_ager_key ) secondsensortype = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.sensorsecondtype_key) # disabled if 0 - temp_ist = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_temperature_key) - humidity_ist = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_humidity_key) + temp_ist = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.temperature_avg_key) + humidity_ist = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.humidity_avg_key) temp_soll = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.setpoint_temperature_key) humitidy_soll = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.setpoint_humidity_key) humabs_ext = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.second_sensor_humidity_abs_key) - humabs = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_humidity_abs_key) + humabs = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.humidity_abs_avg_key) await self.client.set('txt_temp_set.txt', "%.1f" % (temp_soll)) await self.client.set('txt_humid_set.txt', "%.1f" % (humitidy_soll)) @@ -667,6 +714,9 @@ async def process_page3(self): async def process_page4(self): await self.update_extended_values() + + async def process_page_6_14(self): + await self.update_info_values() async def process_page9(self): await self.update_states() @@ -678,6 +728,22 @@ async def process_page12(self): async def process_page_17_19(self): await self.update_page_17_19_values() + + async def process_wifi_btn(self): + len_wifi_ssid = len(self.get_wifi_ssid()) + len_ip_address = len(self.get_ip_address()) + # cl_fact_logger.get_instance().info('len(wifi_ssid) :' + str(len_wifi_ssid) + ' len(ip_address) :' + str(len_ip_address)) + + if (len_wifi_ssid == 0 and len_ip_address == 0): # no WLAN + await self.client.set('btn_wifi.pic', 55) + await self.client.set('btn_wifi.pic2', 55) + elif (len_wifi_ssid != 0 and len_ip_address != 0): # client mode, standard + await self.client.set('btn_wifi.pic', 44) + await self.client.set('btn_wifi.pic2', 44) + elif (len_wifi_ssid == 0 and len_ip_address != 0 ): # AP mode + await self.client.set('btn_wifi.pic', 54) + await self.client.set('btn_wifi.pic2', 54) + async def run_client(self): self.button_event = asyncio.Event() @@ -697,7 +763,7 @@ async def run_client(self): self.wakeup_task = self.loop.create_task(self.wakeup_waiter(self.wakeup_event)) except Exception as e: cl_fact_logger.get_instance().error('run_client exception1: ' + str(e)) - cl_fact_logger.get_instance().error('Could not connect to Nextion client. Possible HDMI display not connected') + cl_fact_logger.get_instance().error(_('Could not connect to Nextion client. Possible HMI display not connected')) while not self.stop_event.is_set(): await asyncio.sleep(1) return @@ -717,17 +783,24 @@ async def run_client(self): elif self.current_page_id == 4: await self.process_page4() elif self.current_page_id == 5: - await self.show_offline() + await self.show_offline() + elif self.current_page_id == 6: + await self.process_page_6_14() elif self.current_page_id == 9: await self.process_page9() elif self.current_page_id == 12: - await self.process_page12() + await self.process_page12() + elif self.current_page_id == 14: + await self.process_page_6_14() elif self.current_page_id == 17: await self.process_page_17_19() elif self.current_page_id == 19: await self.process_page_17_19() elif self.current_page_id == 13: await self.show_offline() + + if not(self.current_page_id == 0 or self.current_page_id == 5 or self.current_page_id == 8 or self.current_page_id == 13): + await self.process_wifi_btn() except Exception as e: cl_fact_logger.get_instance().debug('run_client exception2: ' + str(e)) @@ -738,7 +811,7 @@ async def run_client(self): await asyncio.sleep(3) - cl_fact_logger.get_instance().info('Nextion client run-loop finished') + cl_fact_logger.get_instance().info(_('Nextion client run-loop finished')) def inner_ctrl_c_signal_handler(self, sig, frame): self.stop_event.set() @@ -791,7 +864,7 @@ def run(self): finally: #cl_fact_logger.get_instance().info('after finally') - cl_fact_logger.get_instance().info('Nextion client stopped') + cl_fact_logger.get_instance().info(_('Nextion client stopped')) self.loop.close() async def show_offline(self): diff --git a/opt/pi-ager/pi_ager_cl_uptime.py b/opt/pi-ager/pi_ager_cl_uptime.py new file mode 100644 index 000000000..22e80efbd --- /dev/null +++ b/opt/pi-ager/pi_ager_cl_uptime.py @@ -0,0 +1,118 @@ +#!/usr/bin/python3 +""" + thread for counting active hours +""" +import RPi.GPIO as gpio +import pi_ager_names +import pi_ager_gpio_config + +if __name__ == '__main__': + # init global threading.lock + import globals + globals.init() + import gettext + _ = gettext.gettext + gpio.setwarnings(False) + gpio.setmode(pi_ager_gpio_config.board_mode) + gpio.setup(pi_ager_gpio_config.gpio_uv, gpio.OUT ) + +import pi_ager_database +from abc import ABC +import time +import datetime +from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +from main.pi_ager_cl_logger import cl_fact_logger +import threading + +class cl_uptime_thread(threading.Thread): + def __init__(self): + super().__init__() + self.stop_received = False + self.last_time = int(time.time()) + self.uv_light_uptime = 0 + self.pi_ager_uptime = 0 + self.loop_count = 0 + + def run(self): + try: + cl_fact_logger.get_instance().info(_('Start uptime loop at') + ' ' + time.strftime('%H:%M:%S', time.localtime())) + # here init active_seconds from db + row = pi_ager_database.get_table_row(pi_ager_names.time_meter_table, 1) + self.uv_light_uptime = row[pi_ager_names.uv_light_seconds_field] + self.pi_ager_uptime = row[pi_ager_names.pi_ager_seconds_field] + self.last_time = int(time.time()) + self.do_uptime_loop() + + except Exception as cx_error: + cl_fact_logic_messenger().get_instance().handle_exception(cx_error) + + finally: + cl_fact_logger.get_instance().info(_('Uptime loop stopped at') + ' ' + time.strftime('%H:%M:%S', time.localtime())) + + def do_uptime_loop(self): + while not self.stop_received and threading.main_thread().is_alive(): + self.loop_count += 1 + if (self.loop_count > 10): # take timestamp every 10 seconds + self.loop_count = 0 + new_time_stamp = int(time.time()) + if gpio.input(pi_ager_gpio_config.gpio_uv) == False: # uv light is active + time_diff = new_time_stamp - self.last_time + # add here time-div to active hours_s + row = pi_ager_database.get_table_row(pi_ager_names.time_meter_table, 1) + self.uv_light_uptime = row[pi_ager_names.uv_light_seconds_field] + time_diff + pi_ager_database.update_table_field(pi_ager_names.time_meter_table, pi_ager_names.uv_light_seconds_field, self.uv_light_uptime) + + status_pi_ager = int(pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.status_pi_ager_key)) + if (status_pi_ager == True): # Pi-Ager running? + time_diff = new_time_stamp - self.last_time + row = pi_ager_database.get_table_row(pi_ager_names.time_meter_table, 1) + self.pi_ager_uptime = row[pi_ager_names.pi_ager_seconds_field] + time_diff + pi_ager_database.update_table_field(pi_ager_names.time_meter_table, pi_ager_names.pi_ager_seconds_field, self.pi_ager_uptime) + + self.last_time = new_time_stamp + # print("uv light uptime : " + str(datetime.timedelta(seconds=int(self.uv_light_uptime))) + " pi_ager uptime : " + str(datetime.timedelta(seconds=int(self.pi_ager_uptime)))) + time.sleep(1) + +class cl_fact_uptime(ABC): + __o_instance = None + + @classmethod + def set_instance(self, i_instance): + """ + Factory method to set the instance + """ + cl_fact_uptime.__o_instance = i_instance + + @classmethod + def get_instance(self): + """ + Factory method to get the instance + """ + if cl_fact_uptime.__o_instance is not None: + return(cl_fact_uptime.__o_instance) + cl_fact_uptime.__o_instance = cl_uptime_thread() + return(cl_fact_uptime.__o_instance) + + def __init__(self): + """ + Constructor factory + """ + pass + +def main(): + uptime_thread = cl_fact_uptime().get_instance() + uptime_thread.start() + + try: + while True: + time.sleep(1) + + except KeyboardInterrupt: + print("Ctrl-c received! Sending Stop to thread...") + uptime_thread.stop_received = True + + uptime_thread.join() + print('finis.') + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/opt/pi-ager/pi_ager_database.py b/opt/pi-ager/pi_ager_database.py index 93ba05681..07202a9fb 100644 --- a/opt/pi-ager/pi_ager_database.py +++ b/opt/pi-ager/pi_ager_database.py @@ -343,30 +343,6 @@ def get_scale_settings_from_table(scale_settings_table): close_database() return rows -def read_config(): - """ - function for reading the config table - """ - global cursor - with globals.lock: - open_database() - execute_query('SELECT * FROM ' + pi_ager_names.config_settings_table + ' WHERE ' + pi_ager_names.key_field + ' ="sensortype" OR "key"="language" OR "key"="switch_on_cooling_compressor" OR "key" = "switch_off_cooling_compressor"OR "key"="switch_on_humidifier" OR "key" = "switch_off_humidifier" OR "key" = "delay_humidify" OR "key" = "uv_modus" OR "key" = "uv_duration" OR "key" = "uv_period" OR "key" = "switch_on_uv_hour" OR "key" = "switch_on_uv_minute" OR "key" = "light_modus" OR "key" = "light_duration" OR "key" = "light_period" OR "key" = "switch_on_light_hour" OR "key" = "switch_on_light_minute" OR "key" = "dehumidifier_modus" OR "key" = "referenceunit_scale1" OR "key" = "referenceunit_scale2"') - rows = cursor.fetchall() - close_database() - return rows - -def read_settings(): - """ - function for reading the settings table - """ - global cursor - with globals.lock: - open_database() - execute_query('SELECT * FROM ' + pi_ager_names.config_settings_table + ' WHERE ' + pi_ager_names.key_field + ' ="modus" OR "key"="setpoint_temperature" OR "key"="setpoint_humidity" OR "key"="circulation_air_period" OR "key"="circulation_air_duration" OR "key"="exhaust_air_period" OR "key"="exhaust_air_duration"') - rows = cursor.fetchall() - close_database() - return rows - def read_agingtable_name_from_config(): """ function for reading the currently set agingtabletable @@ -414,18 +390,15 @@ def get_status_uv_manual(): return status_uv_manual -def write_all_sensordata(loopnumber, sensor_temperature, sensor_humidity, sensor_dewpoint, second_sensor_temperature, second_sensor_humidity, second_sensor_dewpoint, sensor_meat1, sensor_meat2, sensor_meat3, sensor_meat4, sensor_humidity_abs, second_sensor_humidity_abs): +def write_all_sensordata(sensor_temperature, sensor_humidity, sensor_dewpoint, second_sensor_temperature, second_sensor_humidity, second_sensor_dewpoint, sensor_meat1, sensor_meat2, sensor_meat3, sensor_meat4, sensor_humidity_abs, second_sensor_humidity_abs, tempintavg, humintavg): """ function for writing diagram-relevant sensor data """ - save_loop = int(get_table_value(pi_ager_names.config_settings_table, pi_ager_names.save_temperature_humidity_loops_key)) + current_time = str(get_current_time()) - if loopnumber % (save_loop * 2) == 0: # schreibt Daten für die Diagramme alle n Loops in die DB, measurement loop von 10s auf 5s verkürzt - current_time = str(get_current_time()) # get current_time timestamp the same for all sensor data tables - - with globals.lock: - open_database() - execute_query('INSERT INTO ' + pi_ager_names.all_sensors_table + '(' + + with globals.lock: + open_database() + execute_query('INSERT INTO ' + pi_ager_names.all_sensors_table + '(' + str(pi_ager_names.tempint_field) + ',' + str(pi_ager_names.tempext_field) + ',' + str(pi_ager_names.humint_field) + ',' + @@ -438,7 +411,9 @@ def write_all_sensordata(loopnumber, sensor_temperature, sensor_humidity, sensor str(pi_ager_names.ntc2_field) + ',' + str(pi_ager_names.ntc3_field) + ',' + str(pi_ager_names.ntc4_field) + ',' + - str(pi_ager_names.last_change_field) +') VALUES ('+ + str(pi_ager_names.last_change_field) + ',' + + str(pi_ager_names.tempintavg_field) + ',' + + str(pi_ager_names.humintavg_field) + ') VALUES ('+ ('NULL' if sensor_temperature == None else str(sensor_temperature)) + ', ' + ('NULL' if second_sensor_temperature == None else str(second_sensor_temperature)) + ', ' + ('NULL' if sensor_humidity == None else str(sensor_humidity)) + ', ' + @@ -451,8 +426,10 @@ def write_all_sensordata(loopnumber, sensor_temperature, sensor_humidity, sensor ('NULL' if sensor_meat2 == None else str(sensor_meat2)) + ', ' + ('NULL' if sensor_meat3 == None else str(sensor_meat3)) + ', ' + ('NULL' if sensor_meat4 == None else str(sensor_meat4)) + ', ' + - current_time + ')') - close_database() + current_time + ', ' + + ('NULL' if tempintavg == None else str(tempintavg)) + ', ' + + ('NULL' if humintavg == None else str(humintavg)) + ')') + close_database() def write_current(sensor_temperature, status_heater, status_exhaust_air, status_cooling_compressor, status_circulating_air, sensor_humidity, sensor_dewpoint, sensor_humidity_abs, second_sensor_temperature,second_sensor_humidity, second_sensor_dewpoint, second_sensor_humidity_abs, status_uv, status_light, status_humidifier, status_dehumidifier, temp_sensor1_data, temp_sensor2_data, temp_sensor3_data, temp_sensor4_data): @@ -609,34 +586,6 @@ def write_stop_in_database(module_key): """ write_startstop_status_in_database(module_key, 0) -def write_config(sensortype, language, switch_on_cooling_compressor, switch_off_cooling_compressor, switch_on_humidifier, switch_off_humidifier, delay_humidify, uv_modus, uv_duration, uv_period, switch_on_uv_hour, switch_on_uv_minute, light_modus, light_duration, light_period, switch_on_light_hour, switch_on_light_minute, dehumidifier_modus, referenceunit_scale1, referenceunit_scale2): - """ - function for writing the config values - """ - with globals.lock: - open_database() - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(sensortype) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="sensortype"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(language) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="language"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(switch_on_cooling_compressor) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="switch_on_cooling_compressor"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(switch_off_cooling_compressor) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="switch_off_cooling_compressor"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(switch_on_humidifier) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="switch_on_humidifier"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(switch_off_humidifier) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="switch_off_humidifier"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(delay_humidify) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="delay_humidify"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(uv_modus) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="uv_modus"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str((uv_duration / 60)) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="uv_duration"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str((uv_period /60)) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="uv_period"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(switch_on_uv_hour) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="switch_on_uv_hour"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(switch_on_uv_minute) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="switch_on_uv_minute"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(light_modus) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="light_modus"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str((light_duration / 60)) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' ="light_duration"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str((light_period / 60)) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' = "' + pi_ager_names.light_period_key + '"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(switch_on_light_hour) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' = "' + pi_ager_names.switch_on_light_hour_key + '"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(switch_on_light_minute) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' = "' + pi_ager_names.switch_on_light_minute_key + '"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(dehumidifier_modus) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' = "' + pi_ager_names.dehumidifier_modus_key + '"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(referenceunit_scale1) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' = "' + pi_ager_names.referenceunit_scale1_key + '"') - execute_query('UPDATE ' + pi_ager_names.config_settings_table + ' SET "' + pi_ager_names.value_field + '" = "' + str(referenceunit_scale2) +'" , "' + pi_ager_names.last_change_field + '" = ' + str(get_current_time()) +' WHERE ' + pi_ager_names.key_field + ' = "' + pi_ager_names.referenceunit_scale2_key + '"') - close_database() - def write_changed_values(status_heater, status_exhaust_air, status_cooling_compressor, status_circulating_air, status_uv, status_light, status_humidifier, status_dehumidifier): """ function for writing with modified sensor and status values @@ -698,4 +647,48 @@ def update_nextion_table( progress, status ): with globals.lock: open_database() execute_query('UPDATE ' + pi_ager_names.nextion_table + ' SET ' + pi_ager_names.progress_field + ' = ' + str(progress) + ', ' + pi_ager_names.status_field + ' = "' + status + '" WHERE id = 1' ) - close_database() \ No newline at end of file + close_database() + + +def update_table_field( table, field, value ): + """ + function to update a value in a table with field + """ + with globals.lock: + open_database() + execute_query('UPDATE ' + table + ' SET ' + field + '=' + str(value) + ' WHERE id = 1' ) + close_database() + +def is_table_empty( table ): + """ + check if table is empty + return True, if empty, else False + """ + sql = 'SELECT COUNT(*) as count FROM ' + table + with globals.lock: + open_database() + execute_query(sql) + row = cursor.fetchone() + close_database() + + if (row == None): + return True + numRows = row['count'] + if (numRows == 0): + return True + else: + return False + +def clear_atc_data(): + """ + clear MiTemp sensor data in DB + """ + if (is_table_empty('atc_data') == False): + sql = 'UPDATE atc_data SET temperature = NULL, humidity = NULL, battvolt = NULL, battpercent = NULL, last_change = NULL WHERE id = 1' + with globals.lock: + open_database() + execute_query(sql) + close_database() + + + \ No newline at end of file diff --git a/opt/pi-ager/pi_ager_init.py b/opt/pi-ager/pi_ager_init.py index 1caf91736..6672fce08 100644 --- a/opt/pi-ager/pi_ager_init.py +++ b/opt/pi-ager/pi_ager_init.py @@ -48,58 +48,6 @@ def set_sensortype(): # logger.info(_('sensortype set to') + ' ' + sensorname) cl_fact_logger.get_instance().info(_('sensortype set to') + ' ' + sensorname) -""" - if sensortype == 1: #DHT - sensor = Adafruit_DHT.DHT11 - sensorname = 'DHT11' - sensorvalue = 1 - elif sensortype == 2: #DHT22 - sensor = Adafruit_DHT.DHT22 - sensorname = 'DHT22' - sensorvalue = 2 - elif sensortype == 3: #SHT - #sensor = Adafruit_DHT.AM2302 - sensor = 'SHT' - sensorname = 'SHT' - sensorvalue = 3 -""" -# check_sensor(sensorname, sensor) - - -def check_sensor(sensorname, sensor): - """ - checking wired sensor - """ - global sensortype - # logger.debug('check_sensor()') - cl_fact_logger.get_instance().debug('check_sensor()') - try: - if sensorname == 'SHT': - sensor_sht = pi_sht1x.SHT1x(pi_ager_names.gpio_sensor_data, pi_ager_names.gpio_sensor_sync, gpio_mode=pi_ager_names.board_mode) - sensor_sht.read_temperature() - sensor_sht.read_humidity() - value_sht_temperature = sensor_sht.temperature_celsius - value_sht_humidity = sensor_sht.humidity - - if value_sht_temperature > 100: - raise Exception - else: - value_dht_humidity, value_temperature = Adafruit_DHT.read_retry(sensor, pi_ager_names.gpio_sensor_data) - - if value_temperature > 100: - raise Exception - except: - if sensorname == 'SHT': - sensortype = 2 - elif sensorname == 'DHT22': - sensortype = 1 - else: - sensortype = 3 - pi_ager_database.update_value_in_table(pi_ager_names.config_settings_table, pi_ager_names.sensortype_key, sensortype) - # logger.info(_('wrong sensortype in settings')) - cl_fact_logger.get_instance().info(_('wrong sensortype in settings')) - set_sensortype() - def set_system_starttime(): """ setting starttimes @@ -159,16 +107,3 @@ def setup_GPIO(): pi_ager_gpio_config.defaultGPIO() loopcounter = 0 # Zaehlt die Durchlaeufe des Mainloops - -# Einschalttemperatur -switch_on_cooling_compressor = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_cooling_compressor_key) -# Ausschalttemperatur -switch_off_cooling_compressor = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_off_cooling_compressor_key) -# Einschaltfeuchte -switch_on_humidifier = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_humidifier_key) -# Ausschaltfeuchte -switch_off_humidifier = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_off_humidifier_key) -# Luftbefeuchtungsverzoegerung -delay_humidify = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.delay_humidify_key) - - diff --git a/opt/pi-ager/pi_ager_loop.py b/opt/pi-ager/pi_ager_loop.py index 5915cf80a..f05d73459 100644 --- a/opt/pi-ager/pi_ager_loop.py +++ b/opt/pi-ager/pi_ager_loop.py @@ -14,13 +14,14 @@ import pi_ager_names import pi_ager_paths import pi_ager_init +import math import pi_ager_gpio_config # import pi_ager_organization import pi_ager_mcp3204 from time import ctime as convert -from main.pi_ager_cx_exception import (cx_i2c_sht_temperature_crc_error, cx_i2c_sht_humidity_crc_error, cx_i2c_bus_error) +from main.pi_ager_cx_exception import (cx_i2c_sht_temperature_crc_error, cx_i2c_sht_humidity_crc_error, cx_i2c_bus_error, cx_i2c_aht_crc_error) from messenger.pi_ager_cl_alarm import cl_fact_logic_alarm from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type, cl_fact_second_sensor_type @@ -30,7 +31,8 @@ from main.pi_ager_cl_logger import cl_fact_logger from pi_ager_cl_nextion import cl_fact_nextion from threading import Timer - +from collections import deque + import globals system_shutdown = False @@ -47,6 +49,37 @@ # #------------------------------------------------------------------------------------- + +# class for mean value evaluation of temperature and humidity +class average_data: + def __init__(self, maxlen = 30): + list_of_values = [] + self.value_fifo = deque(list_of_values, maxlen) # list of values initially empty + + def insert_value(self, value): + self.value_fifo.append( value ) + + def eval_average(self): + l = len(self.value_fifo) + if (l == 0): + return None + s = sum(self.value_fifo) + average = s/l + return average + + def change_maxlen(self, maxlen): + self.value_fifo = deque(self.value_fifo, maxlen) + + def clear_fifo( self ): + self.value_fifo.clear() + + def eval_fifo_len(self): + return len(self.value_fifo) + +# instance and initialize classes for average data +average_data_temp = average_data() +average_data_hum = average_data() + #------------------------------------------------------------------------------------- # for UPS Bat Low, Power Monitor and Switch, check to issue events ups_bat_low = True # akku ok @@ -58,15 +91,15 @@ #------------------------------------------------------------------------------------- def start_mi_thermometer(): - # check if /home/pi/MiTemperature2/LYWSD03MMC.py is allready running, if not then start this process - stream = os.popen('pgrep -lf python3 | grep LYWSD03MMC.py | wc -l') + # check if /opt/ATC_MiThermometer/ATC_xxxxxx.py is allready running, if not then start this process + stream = os.popen('pgrep -a python3 | grep ATC_xxxxxx.py | wc -l') output = stream.read().rstrip('\n') - cl_fact_logger.get_instance().debug('/opt/MiTemperature2/LYWSD03MMC.py checking: ' + str(output)) + cl_fact_logger.get_instance().debug('/opt/ATC_MiThermometer/ATC_xxxxxx.py checking: ' + str(output)) if (output == '0'): - cl_fact_logger.get_instance().debug('/home/pi/MiTemperature2/LYWSD03MMC.py starting') - # os.system('/home/pi/MiTemperature2/LYWSD03MMC.py --atc --callback MiCallback.sh --devicelistfile /home/pi/MiTemperature2/my_thermometer.txt -odl >/home/pi/MiTemperature2/LYWSD03MMC.log &') - os.system('/opt/MiTemperature2/LYWSD03MMC.py --atc --callback MiCallback.sh --devicelistfile /opt/MiTemperature2/my_thermometer.txt -odl >/dev/null 2>/dev/null &') - cl_fact_logger.get_instance().debug('/opt/MiTemperature2/LYWSD03MMC.py started') + cl_fact_logger.get_instance().debug('/opt/ATC_MiThermometer/ATC_xxxxxx.py starting') + os.system('/opt/ATC_MiThermometer/ATC_xxxxxx.py >/dev/null 2>/dev/null &') +# os.system('/opt/MiTemperature2/LYWSD03MMC.py --atc --callback MiCallback.sh --devicelistfile /opt/MiTemperature2/my_thermometer.txt -odl >/dev/null 2>/dev/null &') + cl_fact_logger.get_instance().debug('/opt/ATC_MiThermometer/ATC_xxxxxx.py started') def autostart_loop(): """ @@ -74,16 +107,19 @@ def autostart_loop(): """ global status_pi_ager global system_shutdown + # global logger try: while not system_shutdown: status_pi_ager = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.status_pi_ager_key) second_sensor_type = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.sensorsecondtype_key)) + # get type number for MiThermometer from second sensor dictionary + Mi_Thermometer_type_from_dictionary = [k for k, v in pi_ager_names.SUPPORTED_SECOND_SENSOR_TYPES.items() if v == 'MiThermometer'][0] cl_fact_logger.get_instance().update_logger_loglevels() cl_fact_logger.get_instance().debug('autostart_loop ' + time.strftime('%H:%M:%S', time.localtime())) # enter main loop when start is true if status_pi_ager == 1: - if (second_sensor_type == 6): + if (second_sensor_type == Mi_Thermometer_type_from_dictionary): start_mi_thermometer() doMainLoop() @@ -93,8 +129,9 @@ def autostart_loop(): time.sleep(5) except Exception as cx_error: cl_fact_logic_messenger().get_instance().handle_exception(cx_error) + -def get_sensordata(sht_exception_count, humidity_exception_count, temperature_exception_count, dewpoint_exception_count, humidity_abs_exception_count, sensordata_exception_count): +def get_sensordata(): """ try to read sensordata """ @@ -106,7 +143,7 @@ def get_sensordata(sht_exception_count, humidity_exception_count, temperature_ex global second_sensor_temperature_big global second_sensor_dewpoint_big global second_sensor_humidity_abs_big - + last_temperature = None last_humidity = None last_dewpoint = None @@ -119,15 +156,16 @@ def get_sensordata(sht_exception_count, humidity_exception_count, temperature_ex sensordata={} sensorname = cl_fact_main_sensor_type.get_instance().get_sensor_type_ui() + sensortype = int(cl_fact_main_sensor_type.get_instance().get_sensor_type()) + second_sensorname = None cl_fact_logger.get_instance().debug("sensorname: " + str(sensorname)) - cl_fact_logger.get_instance().debug("sensortype: " + str(cl_fact_main_sensor_type.get_instance().get_sensor_type())) + cl_fact_logger.get_instance().debug("sensortype: " + str(sensortype)) try: - if sensorname == 'DHT11' or sensorname == 'DHT22' or sensorname == 'SHT75': + if sensortype >= 1 and sensortype <= 3: try: main_sensor = cl_fact_active_main_sensor().get_instance() - main_sensor.execute() measured_data = main_sensor.get_current_data() (sensor_temperature_big, sensor_humidity_big, sensor_dewpoint_big, sensor_humidity_abs_big) = measured_data cl_fact_logger.get_instance().debug('sensor_temperature_big: ' + str(sensor_temperature_big)) @@ -135,43 +173,30 @@ def get_sensordata(sht_exception_count, humidity_exception_count, temperature_ex cl_fact_logger.get_instance().debug('sensor_dewpoint_big: ' + str(sensor_dewpoint_big)) cl_fact_logger.get_instance().debug('sensor_humidity_abs_big: ' + str(sensor_humidity_abs_big)) - except pi_sht1x.sht1x.SHT1xError as cx_error: + except Exception as cx_error: cl_fact_logic_messenger().get_instance().handle_exception(cx_error) - elif sensorname == 'SHT3x' or sensorname == 'SHT85': #SH3x + elif sensortype >= 4 : # SHT and AHT sensors try: - i2c_address_main_sensor = 0x44 #0x45 + i2c_address_main_sensor = pi_ager_names.I2C_SENSOR_ADDRESS[sensortype] main_sensor = cl_fact_active_main_sensor().get_instance(i_address = i2c_address_main_sensor) - main_sensor.execute() measured_data = main_sensor.get_current_data() (sensor_temperature_big, sensor_humidity_big, sensor_dewpoint_big, sensor_humidity_abs_big) = measured_data - - # cl_fact_logger.get_instance().debug('sensor_temperature_big: ' + str(sensor_temperature_big)) - # cl_fact_logger.get_instance().debug('sensor_humidity_big: ' + str(sensor_humidity_big)) - # cl_fact_logger.get_instance().debug('sensor_dewpoint_big: ' + str(sensor_dewpoint_big)) - # cl_fact_logger.get_instance().debug('sensor_humidity_abs_big: ' + str(sensor_humidity_abs_big)) - except OSError as cx_error: - cl_fact_i2c_bus_logic().set_instance(None) + except Exception as cx_error: cl_fact_logic_messenger().get_instance().handle_exception(cx_error) - - except (cx_i2c_sht_temperature_crc_error, - cx_i2c_sht_humidity_crc_error, - cx_i2c_bus_error ) as cx_error: - cl_fact_logic_messenger().get_instance().handle_exception(cx_error) - + """ - Zweiter Sensor SHT3x oder SHT85 + Zweiter Sensor """ - second_sensorname = cl_fact_second_sensor_type.get_instance().get_sensor_type_ui() + second_sensorname = cl_fact_second_sensor_type.get_instance().get_sensor_type_ui() + second_sensortype = cl_fact_second_sensor_type.get_instance().get_sensor_type() cl_fact_logger.get_instance().debug('Second sensor is: ' + str(second_sensorname)) - if second_sensorname == 'SHT3x' or second_sensorname == 'SHT85': - + if second_sensortype >= 4 and second_sensortype <= 13: try: - i2c_address_second_sensor = 0x45 + i2c_address_second_sensor = pi_ager_names.I2C_SENSOR_ADDRESS[second_sensortype] second_sensor = cl_fact_active_second_sensor().get_instance(i_address = i2c_address_second_sensor) - second_sensor.execute() measured_second_data = second_sensor.get_current_data() (second_sensor_temperature_big, second_sensor_humidity_big, second_sensor_dewpoint_big, second_sensor_humidity_abs_big) = measured_second_data @@ -180,151 +205,28 @@ def get_sensordata(sht_exception_count, humidity_exception_count, temperature_ex # cl_fact_logger.get_instance().debug('second_sensor_dewpoint_big: ' + str(second_sensor_dewpoint_big)) # cl_fact_logger.get_instance().debug('second_sensor_humidity_abs_big: ' + str(second_sensor_humidity_abs_big)) - except OSError as cx_error: - cl_fact_i2c_bus_logic().set_instance(None) - cl_fact_logic_messenger().get_instance().handle_exception(cx_error) - - except (cx_i2c_sht_temperature_crc_error, cx_i2c_sht_humidity_crc_error, cx_i2c_bus_error ) as cx_error: + except Exception as cx_error: cl_fact_logic_messenger().get_instance().handle_exception(cx_error) - if second_sensorname == 'MiThermometer': + elif second_sensorname == 'MiThermometer': second_sensor = cl_fact_active_second_sensor().get_instance() - # second_sensor.execute() measured_second_data = second_sensor.get_current_data() (second_sensor_temperature_big, second_sensor_humidity_big, second_sensor_dewpoint_big, second_sensor_humidity_abs_big) = measured_second_data - + #cl_fact_logger.get_instance().debug('Second sensor end: ' + str(second_sensorname)) """ - Zweiter Sensor SHT3x oder SHT85 Ende + Zweiter Sensor Ende """ - #cl_fact_logger.get_instance().debug('After Second sensor end: ' + str(second_sensorname)) - last_temperature = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_temperature_key) - last_humidity = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_humidity_key) - last_dewpoint = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_dewpoint_key) - last_humidity_abs = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.sensor_humidity_abs_key) - - if last_temperature is not None and last_humidity is not None: - sensor_temperature = round(sensor_temperature_big,2) - sensor_humidity = round(sensor_humidity_big,2) - sensor_dewpoint = round(sensor_dewpoint_big,2) - sensor_humidity_abs = round(sensor_humidity_abs_big,2) - second_sensor_temperature = round(second_sensor_temperature_big,2) if second_sensor_temperature_big is not None else None - second_sensor_humidity = round(second_sensor_humidity_big,2) if second_sensor_humidity_big is not None else None - second_sensor_dewpoint = round(second_sensor_dewpoint_big,2) if second_sensor_dewpoint_big is not None else None - second_sensor_humidity_abs = round(second_sensor_humidity_abs_big,2) if second_sensor_humidity_abs_big is not None else None - elif sensor_humidity_big is not None and sensor_temperature_big is not None and sensor_dewpoint_big is not None: # and last_temperaure is not None and last_humidity is not None: - #sensor_temperature_big = float(sensor_temperature_big) - sensor_temperature = round(sensor_temperature_big,2) - sensor_humidity = round(sensor_humidity_big,2) - sensor_dewpoint = round(sensor_dewpoint_big,2) - sensor_humidity_abs = round(sensor_humidity_abs_big,2) - second_sensor_temperature = round(second_sensor_temperature_big,2) if second_sensor_temperature_big is not None else None - second_sensor_humidity = round(second_sensor_humidity_big,2) if second_sensor_humidity_big is not None else None - second_sensor_dewpoint = round(second_sensor_dewpoint_big,2) if second_sensor_dewpoint_big is not None else None - second_sensor_humidity_abs = round(second_sensor_humidity_abs_big,2) if second_sensor_humidity_abs_big is not None else None - - #temperature - if last_temperature == 0: - deviation_temperature = sensor_temperature - else: - deviation_temperature = abs((sensor_temperature/last_temperature * 100) - 100) - - #humidity - if last_humidity == 0: - deviation_humidity = sensor_humidity - else: - deviation_humidity = abs((sensor_humidity/last_humidity * 100) - 100) - - #dewpoint - if last_dewpoint == 0: - deviation_dewpoint = sensor_dewpoint - else: - deviation_dewpoint = abs((sensor_dewpoint/last_dewpoint * 100) - 100) - - #humidity abs - if last_humidity_abs == 0: - deviation_humidity_abs = sensor_humidity_abs - else: - deviation_humidity_abs = abs((sensor_humidity_abs/last_humidity_abs * 100) - 100) - - #temperature - if sensor_temperature > 80 or deviation_temperature > 20: - if temperature_exception_count < 10: - countup_values = countup('temperature_exception', temperature_exception_count) - logstring = countup_values['logstring'] - temperature_exception_count = countup_values['counter'] - cl_fact_logger.get_instance().debug(logstring) - time.sleep(1) - recursion = get_sensordata(sht_exception_count, humidity_exception_count, temperature_exception_count, dewpoint_exception_count, humidity_abs_exception_count, sensordata_exception_count) - return recursion - else: - pass - - #humidity - if sensor_humidity > 100 or deviation_humidity > 20: - if humidity_exception_count < 10: - countup_values = countup('humidity_exception', humidity_exception_count) - logstring = countup_values['logstring'] - humidity_exception_count = countup_values['counter'] - cl_fact_logger.get_instance().debug(logstring) - time.sleep(1) - recursion = get_sensordata(sht_exception_count, humidity_exception_count, temperature_exception_count, dewpoint_exception_count, humidity_abs_exception_count, sensordata_exception_count) - return recursion - else: - pass - - #dewpoint - if sensor_dewpoint > 60 or deviation_dewpoint > 20: - if dewpoint_exception_count < 10: - countup_values = countup('dewpoint_exception', dewpoint_exception_count) - logstring = countup_values['logstring'] - dewpoint_exception_count = countup_values['counter'] - cl_fact_logger.get_instance().debug(logstring) - time.sleep(1) - recursion = get_sensordata(sht_exception_count, humidity_exception_count, temperature_exception_count, dewpoint_exception_count, humidity_abs_exception_count, sensordata_exception_count) - return recursion - else: - pass - - #humidity abs - if sensor_humidity_abs > 100 or deviation_humidity_abs > 20: - if humidity_abs_exception_count < 10: - countup_values = countup('humidity_abs_exception', humidity_abs_exception_count) - logstring = countup_values['logstring'] - humidity_abs_exception_count = countup_values['counter'] - cl_fact_logger.get_instance().debug(logstring) - time.sleep(1) - recursion = get_sensordata(sht_exception_count, humidity_exception_count, temperature_exception_count, dewpoint_exception_count, humidity_abs_exception_count, sensordata_exception_count) - return recursion - else: - pass - - elif sensordata_exception_count < 10: - sensor_temperature = None - sensor_humidity = None - sensor_dewpoint = None - sensor_humidity_abs = None - - countup_values = countup('sensordata_exception', sensordata_exception_count) - logstring = countup_values['logstring'] - sensordata_exception_count = countup_values['counter'] - - cl_fact_logger.get_instance().debug(logstring) - time.sleep(1) - recursion = get_sensordata(sht_exception_count, humidity_exception_count, temperature_exception_count, dewpoint_exception_count, humidity_abs_exception_count, sensordata_exception_count) - return recursion - - else: - sensor_temperature = None - sensor_humidity = None - sensor_dewpoint = None - sensor_humidity_abs = None - - logstring = _('Failed to get sensordata.') - cl_fact_logger.get_instance().warning(logstring) - - + sensor_temperature = round(sensor_temperature_big,2) + sensor_humidity = round(sensor_humidity_big,2) + sensor_dewpoint = round(sensor_dewpoint_big,2) + sensor_humidity_abs = round(sensor_humidity_abs_big,2) + second_sensor_temperature = round(second_sensor_temperature_big,2) if second_sensor_temperature_big is not None else None + second_sensor_humidity = round(second_sensor_humidity_big,2) if second_sensor_humidity_big is not None else None + second_sensor_dewpoint = round(second_sensor_dewpoint_big,2) if second_sensor_dewpoint_big is not None else None + second_sensor_humidity_abs = round(second_sensor_humidity_abs_big,2) if second_sensor_humidity_abs_big is not None else None + sensordata['sensor_temperature'] = sensor_temperature sensordata['sensor_humidity'] = sensor_humidity sensordata['sensor_dewpoint'] = sensor_dewpoint @@ -334,37 +236,12 @@ def get_sensordata(sht_exception_count, humidity_exception_count, temperature_ex sensordata['second_sensor_dewpoint'] = second_sensor_dewpoint sensordata['second_sensor_humidity_abs'] = second_sensor_humidity_abs cl_fact_logger.get_instance().debug( sensordata) - - #exit() - + except Exception as cx_error: cl_fact_logic_messenger().get_instance().handle_exception(cx_error) return(sensordata) -def countup(countername, counter): - counter += 1 - if countername == 'sht_exception': - logstring = 'SHT1xError occured, trying again, current number of retries: ' - elif countername == 'humidity_exception': - logstring = 'no plausible humidity value [> 100 or too much deviation], trying again, current number of retries: ' - elif countername == 'humidity_abs_exception': - logstring = 'no plausible humidity abs value [> 100 or too much deviation], trying again, current number of retries: ' - elif countername == 'temperature_exception': - logstring = 'no plausible temperature value [> 60 or too much deviation], trying again, current number of retries: ' - elif countername == 'dewpoint_exception': - logstring = 'no plausible dewpoint value [> 60 or too much deviation], trying again, current number of retries: ' - elif countername == 'sensordata_exception': - logstring = 'sensordata has NULL values, trying again, current number of retries: ' - else: - logstring = 'An Error occured' - logstring = logstring + str(counter) - - countresult = {} - countresult['counter'] = counter - countresult['logstring'] = logstring - return countresult - def set_gpio_value(gpio_number, value): """ setting gpio value @@ -385,7 +262,7 @@ def control_heater(relay_state): global defrost_status if not defrost_status: gpio.output(pi_ager_gpio_config.gpio_heater, relay_state) - + def control_cooling_compressor(relay_state): """ setting gpio for cooler @@ -393,7 +270,7 @@ def control_cooling_compressor(relay_state): global defrost_status if not defrost_status: gpio.output(pi_ager_gpio_config.gpio_cooling_compressor, relay_state) - + def control_circulating_air(relay_state): """ setting gpio for circulation air @@ -450,6 +327,18 @@ def control_defrost(): defrost_cycle_elapsed = False pi_ager_database.write_current_value(pi_ager_names.status_defrost_key, 0) return + +# check if setpoint temperature greater than defrost_temp_limit, then stop defrost cycle + defrost_temp_limit = pi_ager_database.get_table_value_from_field(pi_ager_names.defrost_table, pi_ager_names.defrost_temp_limit_field) # defrost temperature limit + setpoint_temperature = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.setpoint_temperature_key) # setpoint temperature + if (setpoint_temperature >= defrost_temp_limit): + if (defrost_status == 1): + cl_fact_logger.get_instance().info(_('defrost process stopped')) + cl_fact_logic_messenger().get_instance().handle_event('Defrost_stopped') + defrost_status = 0 + defrost_cycle_elapsed = False + pi_ager_database.write_current_value(pi_ager_names.status_defrost_key, 0) + return if (defrost_cycle_elapsed == False): if (defrost_status == 1): @@ -482,7 +371,11 @@ def control_defrost(): pi_ager_database.write_current_value(pi_ager_names.status_defrost_key, 1) gpio.output(pi_ager_gpio_config.gpio_heater, pi_ager_names.relay_on) gpio.output(pi_ager_gpio_config.gpio_cooling_compressor, pi_ager_names.relay_off) - gpio.output(pi_ager_gpio_config.gpio_circulating_air, pi_ager_names.relay_on) + circulate_air = int(pi_ager_database.get_table_value_from_field(pi_ager_names.defrost_table, pi_ager_names.defrost_circulate_air_field)) + if (circulate_air == 1): + gpio.output(pi_ager_gpio_config.gpio_circulating_air, pi_ager_names.relay_on) + else: + gpio.output(pi_ager_gpio_config.gpio_circulating_air, pi_ager_names.relay_off) cl_fact_logger.get_instance().debug('defrost in progress') def status_light_in_current_values_is_on(): @@ -533,6 +426,8 @@ def status_value_has_changed(): global status_dehumidifier # Entfeuchter global status_uv # UV-Licht global status_light # Licht + global sensor_temperature + global sensor_humidity changed = pi_ager_init.loopcounter == 0 log_string_html = pi_ager_names.logspacer2 + '\n' + _('GPIO states') + ':' @@ -545,6 +440,8 @@ def status_value_has_changed(): if gpio.input(pi_ager_gpio_config.gpio_heater) == False: status_heater = 1 + # cabinet simulation +# sensor_temperature += 0.05 if status_heater != current_values[pi_ager_names.status_heater_key]: changed = True log_string_html = log_string_html + ' \n ' + '' + _('heater') + ' ' + _('on') + '' @@ -564,6 +461,8 @@ def status_value_has_changed(): if gpio.input(pi_ager_gpio_config.gpio_cooling_compressor) == False: status_cooling_compressor = 1 + # cabinet simulation +# sensor_temperature -= 0.05 if status_cooling_compressor != current_values[pi_ager_names.status_cooling_compressor_key]: changed = True log_string_html = log_string_html + ' \n ' + '' + _('cooling compressor') + ' ' + _('on') + '' @@ -583,6 +482,9 @@ def status_value_has_changed(): if gpio.input(pi_ager_gpio_config.gpio_humidifier) == False: status_humidifier = 1 + # cabinet simulation +# sensor_humidity += 0.05 + # cl_fact_logger.get_instance().info("Change check: Incremented humidity = " + f'{sensor_humidity:.1f}' + ' %') if status_humidifier != current_values[pi_ager_names.status_humidifier_key]: changed = True log_string_html = log_string_html + ' \n ' + '' + _('humidifier') + ' ' + _('on') + '' @@ -640,6 +542,9 @@ def status_value_has_changed(): if gpio.input(pi_ager_gpio_config.gpio_dehumidifier) == False: status_dehumidifier = 1 + # cabinet simulation +# sensor_humidity -= 0.05 + # cl_fact_logger.get_instance().info("Change check: Decremented humidity = " + f'{sensor_humidity:.1f}' + ' %') if status_dehumidifier != current_values[pi_ager_names.status_dehumidifier_key]: changed = True log_string_html = log_string_html + ' \n ' + '' + _('dehumidifier') + ' ' + _('on') + '' @@ -741,13 +646,30 @@ def invoke_on_failure_event(repeat_event_cycle): next_start_time_on_failure = current_time + repeat_event_cycle cl_fact_logic_messenger().get_instance().handle_event('cooler_turned_on_failure') +#----------------------------------------------------- +last_ac_current = None + def generate_cooler_failure_events(): global cooler_failure_off_repeat_counter global cooler_failure_on_repeat_counter - global temp_sensor4_data # contains AC Current + global cooler_state_fifo + global cooler_state_fifo_maxlen + global last_ac_current + # with each measure cycle update cooler state fifo, relais = off -> -1, relais = on -> +1 + cooler_pio_status = gpio.input(pi_ager_gpio_config.gpio_cooling_compressor) # false --> relay_on, true --> relay_off + if (cooler_pio_status == True): # relais off + cooler_state_fifo.appendleft( -1 ) + else: + cooler_state_fifo.appendleft( 1 ) + + if (last_ac_current == None): + cooler_state_fifo.clear() + return + meat4_sensortype = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.meat4_sensortype_key)) if (meat4_sensortype != 18): # must be ac current sensor + cooler_state_fifo.clear() return current_check_row = pi_ager_database.get_table_row(pi_ager_names.config_current_check_table, 1) @@ -756,17 +678,17 @@ def generate_cooler_failure_events(): if (status_current_check == 0): # current check must be enabled cooler_failure_off_repeat_counter = False cooler_failure_on_repeat_counter = False + cooler_state_fifo.clear() return current_threshold = current_check_row[pi_ager_names.current_threshold_field] repeat_event_cycle = current_check_row[pi_ager_names.repeat_event_cycle_field] * 60 # convert to seconds - ac_current = temp_sensor4_data + ac_current = last_ac_current # cl_fact_logger.get_instance().info(f"cooler check parameter : status = {status_current_check}, threshold = {current_threshold}, repeat cycle = {repeat_event_cycle}") - cooler_status = int(pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.status_cooling_compressor_key)) - cooler_pio_status = gpio.input(pi_ager_gpio_config.gpio_cooling_compressor) # false --> relay_on, true --> relay_off - # check on cooler turned off - if (cooler_status == 0 and cooler_pio_status == True): + sum_of_states = sum(cooler_state_fifo) + # check on cooler turned off for cooler_state_fifo_maxlen states + if (sum_of_states == -cooler_state_fifo_maxlen): if (ac_current > current_threshold): # cl_fact_logger.get_instance().info(f"cooler should be turned off but is not. AC current is {ac_current} A") invoke_off_failure_event(repeat_event_cycle) @@ -776,8 +698,8 @@ def generate_cooler_failure_events(): else: cooler_failure_off_repeat_counter = False - # check on cooler turned on - if (cooler_status == 1 and cooler_pio_status == False): + # check on cooler turned on for cooler_state_fifo_maxlen states + if (sum_of_states == cooler_state_fifo_maxlen): if (ac_current <= current_threshold): # cl_fact_logger.get_instance().info(f"cooler should be turned on but is not. AC current is {ac_current} A") invoke_on_failure_event(repeat_event_cycle) @@ -812,6 +734,7 @@ def generate_ups_bat_events(): cl_fact_logic_messenger().get_instance().handle_event('ups_bat_low') #if the second parameter is empty, the value is taken from the field envent_text in table config_messenger_event if shutdown_on_batlow == 1: cl_fact_logger.get_instance().info(_('Shutdown Pi-Ager now')) + time.sleep(3) # do_system_shutdown() os.system("shutdown -h now") except Exception as cx_error: @@ -895,13 +818,12 @@ def generate_high_limit_reached_event(event_msg): exception_known = cl_fact_logic_messenger().get_instance().handle_exception(cx_error) pass -def check_internal_temperature_limits(): +def check_internal_temperature_limits(temp_avg): global internal_temperature_low_limit_reached global internal_temperature_high_limit_reached global internal_temperature_low_limit global internal_temperature_high_limit global internal_temperature_hysteresis - global sensor_temperature # check if settings in config table changed internal_temperature_low_limit_temp = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.internal_temperature_low_limit_key) @@ -919,60 +841,158 @@ def check_internal_temperature_limits(): internal_temperature_high_limit = internal_temperature_high_limit_temp internal_temperature_hysteresis = internal_temperature_hysteresis_temp - if sensor_temperature != None: - if sensor_temperature <= internal_temperature_low_limit and internal_temperature_low_limit_reached == False: + if temp_avg != None: + if temp_avg <= internal_temperature_low_limit and internal_temperature_low_limit_reached == False: internal_temperature_low_limit_reached = True event_msg = 'Internal temperature low limit ' + str(internal_temperature_low_limit) + '°C ' + 'reached' generate_low_limit_reached_event(event_msg) cl_fact_logger.get_instance().info(event_msg) - if sensor_temperature >= (internal_temperature_low_limit + internal_temperature_hysteresis): + if temp_avg >= (internal_temperature_low_limit + internal_temperature_hysteresis): internal_temperature_low_limit_reached = False - cl_fact_logger.get_instance().debug('Internal temperature ' + str(sensor_temperature) + '°C higher than ' + str(internal_temperature_low_limit + internal_temperature_hysteresis) + '°C. (low limit + hysteresis)') - if sensor_temperature >= internal_temperature_high_limit and internal_temperature_high_limit_reached == False: + cl_fact_logger.get_instance().debug('Internal temperature ' + str(temp_avg) + '°C higher than ' + str(internal_temperature_low_limit + internal_temperature_hysteresis) + '°C. (low limit + hysteresis)') + if temp_avg >= internal_temperature_high_limit and internal_temperature_high_limit_reached == False: internal_temperature_high_limit_reached = True event_msg = 'Internal temperature high limit ' + str(internal_temperature_high_limit) + '°C ' + 'reached' generate_high_limit_reached_event(event_msg) cl_fact_logger.get_instance().info(event_msg) - if sensor_temperature <= (internal_temperature_high_limit - internal_temperature_hysteresis): + if temp_avg <= (internal_temperature_high_limit - internal_temperature_hysteresis): internal_temperature_high_limit_reached = False - cl_fact_logger.get_instance().debug('Internal temperature ' + str(sensor_temperature) + '°C lower than ' + str(internal_temperature_high_limit - internal_temperature_hysteresis) + '°C. (high limit - hysteresis)') + cl_fact_logger.get_instance().debug('Internal temperature ' + str(temp_avg) + '°C lower than ' + str(internal_temperature_high_limit - internal_temperature_hysteresis) + '°C. (high limit - hysteresis)') + +#-------------------------------------------------------------------------------------------- +# generate blocking signal for humidifier depending on cooler_state and dry-aging mode +# blocks humidifier during cooler active and some additional time (delay_humidify), +# when cooler is turned off. +# return False if not blocking humidifier, else return True +#-------------------------------------------------------------------------------------------- +humidifier_block_timer_running = False +humidifier_block_starttime = 0 +last_cooler_state = False + +def generate_humidifier_block(mode): + global humidifier_block_timer_running + global humidifier_block_starttime + global last_cooler_state + + current_cooler_state = not gpio.input(pi_ager_gpio_config.gpio_cooling_compressor) # if false, compressor is on + if (mode == 0): # humidifier disabled, track cooler state and do nothing else + humidifier_block_timer_running = False + last_cooler_state = current_cooler_state + return False + + block_time = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.delay_humidify_key)) # minutes + + if (current_cooler_state == True): # block humidifier + last_cooler_state = current_cooler_state + humidifier_block_timer_running = False + return True + + elif (current_cooler_state == False and last_cooler_state == True): # cooler state changed, cooler turned off, start now timer + if (block_time == 0): + humidifier_block_timer_running = False + last_cooler_state = current_cooler_state + return False # unblock humidifier + else: + humidifier_block_starttime = pi_ager_database.get_current_time() + humidifier_block_timer_running = True + last_cooler_state = current_cooler_state + return True # block humidifier + + elif (current_cooler_state == False and last_cooler_state == False): # cooler state not changed, check if timer running + if (humidifier_block_timer_running == True): + if (pi_ager_database.get_current_time() >= humidifier_block_starttime + block_time * 60): # convert minutes to seconds, wait for delay reached + humidifier_block_timer_running = False + last_cooler_state = current_cooler_state + return False # unblock + else: + last_cooler_state = current_cooler_state + return True # block is still active + else: + last_cooler_state = current_cooler_state + return False # unblock, timer not running -cooling_compressor_request = False -cooling_Delay_timer = None -cooling_Delay_timer_running = False +#------------------------------------------------------------------------------------------- + +def generate_humidifier_failed_event(event_msg): + # generate event + try: + cl_fact_logic_messenger().get_instance().handle_event('humidifier_failure', event_msg) #if the second parameter is empty, the value is taken from the field envent_text in table config_messenger_event + except Exception as cx_error: + exception_known = cl_fact_logic_messenger().get_instance().handle_exception(cx_error) + pass + + +humidifier_monitoring_delay_timer_running = False +humidifier_monitoring_delay_starttime = 0 + +def check_monitoring_humidifier(humidity_avg, humidity_setpoint, delay_monitoring_humidifier, delay_changed, mode, tolerance_monitoring_humidifier, check_monitoring_hum): + global humidifier_monitoring_delay_timer_running + global humidifier_monitoring_delay_starttime -def delay_cooling_compressor_callback(): - global cooling_compressor_request - global cooling_Delay_timer_running - if (cooling_compressor_request == False): # turn on compressor - control_cooling_compressor(pi_ager_names.relay_on) - # gpio.output(pi_ager_gpio_config.gpio_cooling_compressor, False) - cooling_Delay_timer_running = False -# cl_fact_logger.get_instance().info('delay_cooling_compressor_callback finished') + if (check_monitoring_hum == 0): + humidifier_monitoring_delay_timer_running = False + return + + if (mode == 0): # humidifier stopped + humidifier_monitoring_delay_timer_running = False + return + + if (mode == 0): # humidifier stopped + humidifier_monitoring_delay_timer_running = False + return + + if (delay_changed == True): + + humidifier_monitoring_delay_timer_running = False + + if (humidity_avg < (humidity_setpoint - tolerance_monitoring_humidifier)): + if (humidifier_monitoring_delay_timer_running == True): + if (pi_ager_database.get_current_time() >= humidifier_monitoring_delay_starttime + delay_monitoring_humidifier * 60): # convert minutes to seconds, wait for delay reached + humidifier_monitoring_delay_starttime = pi_ager_database.get_current_time() # reset timer, but continue, issue event + event_msg = 'humidity below ' + str(humidity_setpoint) + '%. There may be a problem with the humidifier' + generate_humidifier_failed_event(event_msg) # generate event + else: + humidifier_monitoring_delay_starttime = pi_ager_database.get_current_time() + humidifier_monitoring_delay_timer_running = True + else: # setpoint reached, stop timer + humidifier_monitoring_delay_timer_running = False + + +cooler_delay_timer_running = False +cooler_delay_starttime = 0 + def delay_cooling_compressor( level ): """ when cooling compressor should turned off then next turn-on request will be delayed level false == relay_on == cooler active """ - global cooling_compressor_request - global cooling_Delay_timer_running - global cooling_Delay_timer + global cooler_delay_timer_running + global cooler_delay_starttime # if compressor is currently on and new request (level) should turn off compressor current_state = gpio.input(pi_ager_gpio_config.gpio_cooling_compressor) # if false, compressor is on delay_cooler = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.delay_cooler_key)) - if (current_state == False and level == True and cooling_Delay_timer_running == False): # start timer - cooling_Delay_timer = Timer(delay_cooler, delay_cooling_compressor_callback) - cooling_Delay_timer.start() - cooling_Delay_timer_running = True - # gpio.output(pi_ager_gpio_config.gpio_cooling_compressor, level) - control_cooling_compressor(level) + + if (delay_cooler == 0): # stop timer if running + if (cooler_delay_timer_running == True): + cooler_delay_timer_running = False + + control_cooling_compressor(level) + return + + if (current_state == False and level == True and cooler_delay_timer_running == False): # start timer + cooler_delay_starttime = pi_ager_database.get_current_time() + cooler_delay_timer_running = True + control_cooling_compressor(level) # turn off cooler # cl_fact_logger.get_instance().info('cooling compressor delay timer started') - - cooling_compressor_request = level - if (cooling_Delay_timer_running == False): - # gpio.output(pi_ager_gpio_config.gpio_cooling_compressor, level) + + if (cooler_delay_timer_running == True): # check if timer finished + if (pi_ager_database.get_current_time() >= cooler_delay_starttime + delay_cooler): + cooler_delay_timer_running = False +# cl_fact_logger.get_instance().info('cooling compressor delay timer ended') + + if (cooler_delay_timer_running == False): control_cooling_compressor(level) # cl_fact_logger.get_instance().info('delay_cooling_compressor function finished') @@ -1028,11 +1048,149 @@ def generate_status_change_event(logstring): except Exception as cx_error: exception_known = cl_fact_logic_messenger().get_instance().handle_exception(cx_error) pass + +def simple_cooler_temperature_control(): + # simple 2-point temperature control for cooler, always use primary temperature control hysteresis + global sensor_temperature + global setpoint_temperature + global switch_on_cooling_compressor + global switch_off_cooling_compressor + global cooling_hysteresis_offset # should be positiv + + # check if cooler must be set on or off + if sensor_temperature >= setpoint_temperature + switch_on_cooling_compressor + cooling_hysteresis_offset: + delay_cooling_compressor( pi_ager_names.relay_on) # Kuehlung ein + if sensor_temperature <= setpoint_temperature + switch_off_cooling_compressor + cooling_hysteresis_offset: + delay_cooling_compressor( pi_ager_names.relay_off) # Kuehlung aus + +def simple_heater_temperature_control(): + # simple 2-point temperature control for heater, always use primary hysteresis for heater, but use heating hysteresis offset + global sensor_temperature + global setpoint_temperature + global switch_on_cooling_compressor + global switch_off_cooling_compressor + global heating_hysteresis_offset # should be negativ + + # check if heater must be set on or off + if sensor_temperature <= setpoint_temperature - switch_on_cooling_compressor + heating_hysteresis_offset: + control_heater(pi_ager_names.relay_on) + if sensor_temperature >= setpoint_temperature - switch_off_cooling_compressor + heating_hysteresis_offset: + control_heater(pi_ager_names.relay_off) + +def auto_temperature_control(): + # Automatic 2-point temperature control with 2 actuators, one for cooling and one for heating + # If an external temperature sensor is available, it will be included into the control algorithm + global sensor_temperature + global setpoint_temperature + global second_sensor_temperature + global cooling_hysteresis_offset + global heating_hysteresis_offset + + cooling_hysteresis = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.cooling_hysteresis_key) # primary hysteresis + heating_hysteresis = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.heating_hysteresis_key) # secondary hysteresis + + # check if an external sensor exists and if so check if external temperature is greater than setpoint temperature: + # then activate cooling algorithm. If no external sensor is available, assume cooling cabinet as default + if (second_sensor_temperature == None or second_sensor_temperature > setpoint_temperature): # take primary hysteresis value for cooler + switch_on_cooling_compressor = cooling_hysteresis/2 + switch_off_cooling_compressor = -cooling_hysteresis/2 + switch_on_heater = heating_hysteresis/2 + switch_off_heater = -heating_hysteresis/2 + else: # activate heating alhorithm by exchanging primary and secondary hysteresis values so that heater operates with primary hysteresis + switch_on_cooling_compressor = heating_hysteresis/2 + switch_off_cooling_compressor = -heating_hysteresis/2 + switch_on_heater = cooling_hysteresis/2 + switch_off_heater = -cooling_hysteresis/2 + + # check if cooler or heater must be set on or off + if (sensor_temperature <= setpoint_temperature + switch_off_cooling_compressor + cooling_hysteresis_offset) or (sensor_temperature <= setpoint_temperature + heating_hysteresis_offset + switch_off_heater): + delay_cooling_compressor( pi_ager_names.relay_off) # Kuehlung aus + if (sensor_temperature >= setpoint_temperature - switch_off_heater + heating_hysteresis_offset) or (sensor_temperature >= setpoint_temperature - switch_off_cooling_compressor + cooling_hysteresis_offset): + control_heater(pi_ager_names.relay_off) # Heizung aus + + if (sensor_temperature >= setpoint_temperature + switch_on_cooling_compressor + cooling_hysteresis_offset): # or (sensor_temperature >= setpoint_temperature + switch_on_heater): + delay_cooling_compressor( pi_ager_names.relay_on) # Kuehlung ein + if gpio.input(pi_ager_gpio_config.gpio_heater) == False: # only if heater is on, turn off heater + control_heater(pi_ager_names.relay_off) + + if (sensor_temperature <= setpoint_temperature - switch_on_heater + heating_hysteresis_offset): # or (sensor_temperature <= setpoint_temperature - switch_on_cooling_compressor ): + control_heater(pi_ager_names.relay_on) # Heizung ein + if gpio.input(pi_ager_gpio_config.gpio_cooling_compressor) == False: # only if cooler is on, turn off cooler + delay_cooling_compressor( pi_ager_names.relay_off) # Kuehlung aus + +def eval_switch_on_humidity( setpoint_humidity, humidifier_hysteresis, hysteresis_offset ) : + hum_temp = setpoint_humidity - humidifier_hysteresis/2.0 + hysteresis_offset + return hum_temp if hum_temp > 0 else 0 + +def eval_switch_off_humidity( setpoint_humidity, humidifier_hysteresis, hysteresis_offset, saturation_point ) : + hum_temp = setpoint_humidity + humidifier_hysteresis/2.0 + hysteresis_offset + hum_max = saturation_point - 1 # do not allow values greater saturation point - 1% ! + return hum_max if hum_temp > hum_max else hum_temp + +def eval_switch_on_dehumidity( setpoint_humidity, dehumidifier_hysteresis, hysteresis_offset, saturation_point ) : + hum_temp = setpoint_humidity + dehumidifier_hysteresis/2.0 + hysteresis_offset + hum_max = saturation_point - 1 + return hum_max if hum_temp > hum_max else hum_temp + +def eval_switch_off_dehumidity( setpoint_humidity, dehumidifier_hysteresis, hysteresis_offset ) : + hum_temp = setpoint_humidity - dehumidifier_hysteresis/2.0 + hysteresis_offset + return hum_temp if hum_temp > 0 else 0 + +def simple_humidity_control(): + """ + control humidifier only + """ + global setpoint_humidity + global humidifier_hysteresis + global humidifier_hysteresis_offset + global sensor_humidity + global saturation_point + global status_humidifier + + humidity_low = eval_switch_on_humidity( setpoint_humidity, humidifier_hysteresis, humidifier_hysteresis_offset ) + if sensor_humidity <= humidity_low: + status_humidifier = True + + humidity_high = eval_switch_off_humidity( setpoint_humidity, humidifier_hysteresis, humidifier_hysteresis_offset, saturation_point ) + if sensor_humidity >= humidity_high: + status_humidifier = False + + # cl_fact_logger.get_instance().info("simple_humidity_control : status_humidifier = " + str(status_humidifier) + ".") + +def calc_humidity_abs(temperature, humidity): + """ + calculate humidity absolute derived from temperature and humidity + """ + if humidity == 0: + humidity = 1 + if (temperature >= 0): + a = 7.5 + b = 237.3 + elif (temperature < 0 and temperature > -4): + a = 7.6 + b = 240.7 + elif (temperature <= -4): + a = 9.5 + b = 265.5 + + R = 8314.3 #R* = 8314.3 J/(kmol*K) (universelle Gaskonstante) + mw = 18.016 #mw = 18.016 "kg/kmol (Molekulargewicht des Wasserdampfes) + temperature_kelvin = temperature + 273.15 + SDD = 6.1078 * 10**((a*temperature)/(b+temperature)) + DD = humidity/100 * SDD + v = math.log10(DD/6.1078) +# temperature_dewpoint = b*v/(a-v) + humidity_absolute = 10**5 * mw/R * DD/temperature_kelvin +# cl_fact_logger.get_instance().debug("Calculated DewPoint for Temp %.2f C and Hum %.2f is %.2f, HumAbs is %.2f grams/m³" % (temperature,humidity,temperature_dewpoint, humidity_absolute)) +# calculated_dewpoint = (self._temperature_dewpoint, self._humidity_absolute) +# return(calculated_dewpoint) + return humidity_absolute def doMainLoop(): """ mainloop, pi-ager is running """ + global setpoint_temperature # target temperature global circulation_air_duration # Umluftdauer global circulation_air_period # Umluftperiode global exhaust_air_duration # (Abluft-)luftaustauschdauer @@ -1049,19 +1207,27 @@ def doMainLoop(): global second_sensor_humidity_abs global last_humidity_check_state # für hysterese int/ext abs. humidity check - global switch_on_cooling_compressor # Einschalttemperatur - global switch_off_cooling_compressor # Ausschalttemperatur - global switch_on_humidifier # Einschaltfeuchte - global switch_off_humidifier # Ausschaltfeuchte + global humidifier_hysteresis # Hysterese Befeuchtung + global dehumidifier_hysteresis # Hysterese Entfeuchtung + global humidifier_hysteresis_offset # Hysterese Offset + + global switch_on_heater # Einschalttemperatur + global switch_off_heater # Ausschalttemperatur + + global saturation_point # sensor saturation point + global switch_on_cooling_compressor + global switch_off_cooling_compressor + global cooling_hysteresis_offset + global heating_hysteresis_offset + global settings global status_circulating_air # Umluft global status_exhaust_air # (Abluft-)Luftaustausch global status_heater # Heizung global status_cooling_compressor # Kuehlung global status_humidifier # Luftbefeuchtung - #global counter_humidify # Zaehler Verzoegerung der Luftbefeuchtung - #counter_humidify = 0 - global delay_humidify # Luftbefeuchtungsverzoegerung + global status_dehumidifier # Entfeuchter + global status_exhaust_fan # Variable fuer die "Evakuierung" zur Feuchtereduzierung durch (Abluft-)Luftaustausch global uv_modus # Modus UV-Licht (1 = Periode/Dauer; 2= Zeitstempel/Dauer) @@ -1079,7 +1245,7 @@ def doMainLoop(): global light_period # Periode für Licht global dehumidifier_modus # Modus Entfeuchter (1 = über Abluft, 2 = mit Abluft zusammen [unterstützend]; 3 = anstelle von Abluft) - global status_dehumidifier # Entfeuchter + global status_pi_ager global temp_sensor1_data global temp_sensor2_data @@ -1087,8 +1253,9 @@ def doMainLoop(): global temp_sensor4_data global system_shutdown - global cooling_Delay_timer - global cooling_Delay_timer_running + global cooler_delay_starttime + global cooler_delay_timer_running + #-------------------------------------------- # for event generation global internal_temperature_low_limit_reached @@ -1113,32 +1280,61 @@ def doMainLoop(): global next_start_time_off_failure global next_start_time_on_failure + global cooler_state_fifo # cooler relais statee + global cooler_state_fifo_maxlen + global last_ac_current + + global setpoint_humidity + + global humidifier_monitoring_delay_timer_running + global humidifier_monitoring_delay_starttime + + global humidifier_block_timer_running + global humidifier_block_starttime + global last_cooler_state + #------------------------------------------- # Pruefen Sensor, dann Settings einlesen pi_ager_database.write_start_in_database(pi_ager_names.status_pi_ager_key) status_pi_ager = 1 - count_continuing_emergency_loops = 0 - humidify_delay_switch = False status_exhaust_fan = False # status set bei mode 4 status_exhaust_air = False # relais status --> this is later calculated by status_fan and status_timer and check_int_ext_dewpoint status_exhaust_air_timer = False # status set by timer - + status_humidifier = False # Luftbefeuchtung + status_dehumidifier = False # Entfeuchter last_humidity_check_state = False + pi_ager_database.write_current_value(pi_ager_names.status_humidity_check_key, 0) + cooler_delay_starttime = 0 + cooler_delay_timer_running = False + + humidifier_monitoring_delay_timer_running = False + humidifier_monitoring_delay_starttime = 0 + + humidifier_block_timer_running = False + humidifier_block_starttime = 0 + last_cooler_state = False + #Here get instance of Deviation class cl_fact_logger.get_instance().debug('in doMainLoop()') # Here init uv_period and light_period to detect change in loop - uv_period = float(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.uv_period_key)) - uv_duration = float(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.uv_duration_key)) + uv_period = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.uv_period_key)) + uv_duration = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.uv_duration_key)) uv_modus = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.uv_modus_key)) + switch_on_uv_hour = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_uv_hour_key)) + switch_on_uv_minute = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_uv_minute_key)) + uv_settings_changed = True - light_period = float(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.light_period_key)) - light_duration = float(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.light_duration_key)) - light_modus = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.light_modus_key)) + light_period = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.light_period_key)) + light_duration = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.light_duration_key)) + light_modus = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.light_modus_key)) + switch_on_light_hour = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_light_hour_key)) + switch_on_light_minute = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_light_minute_key)) + light_settings_changed = True # init temperature limits, generate events if temperature is out of limits internal_temperature_low_limit_reached = False @@ -1167,13 +1363,31 @@ def doMainLoop(): cooler_failure_off_repeat_counter = False cooler_failure_on_repeat_counter = False - next_start_time_off_failure = 0; - next_start_time_on_failure = 0; + next_start_time_off_failure = 0 + next_start_time_on_failure = 0 + + state_list = [] + cooler_state_fifo_maxlen = 3 # number of cycles to store in fifo + cooler_state_fifo = deque(state_list, cooler_state_fifo_maxlen) # cooler relais states, initially empty + + # initialize averager for temperature and humidity + temp_avg_maxlen = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.temp_avg_maxlen_key)) + hum_avg_maxlen = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.hum_avg_maxlen_key)) + average_data_temp.change_maxlen(temp_avg_maxlen) + average_data_hum.change_maxlen(hum_avg_maxlen) + + # humidifier monitoring + delay_monitoring_humidifier = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.delay_monitoring_humidifier_key)) + tolerance_monitoring_humidifier = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.tolerance_monitoring_humidifier_key)) + check_monitoring_hum = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.check_monitoring_humidifier_key)) + hum_avg = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.humidity_avg_key) - # mi_data = pi_ager_database.get_table_value_from_field(pi_ager_names.atc_mi_thermometer_data_table, pi_ager_names.mi_data_key) - # cl_fact_logger.get_instance().info(mi_data) - # splited_data = mi_data.split(' ') - # cl_fact_logger.get_instance().info(splited_data) + # dry aging mode + modus = -1 # force modus change + + # cabinet simulation +# sensor_temperature = 20.0 # start value for test +# sensor_humidity = 52 try: while status_pi_ager == 1 and not system_shutdown: @@ -1205,7 +1419,8 @@ def doMainLoop(): temp_sensor2_data = get_temp_sensor_data(sensor2_parameter, 1) temp_sensor3_data = get_temp_sensor_data(sensor3_parameter, 2) temp_sensor4_data = get_temp_sensor_data(sensor4_parameter, 3) - + last_ac_current = pi_ager_database.get_table_value(pi_ager_names.current_values_table, pi_ager_names.temperature_meat4_key) + #Sensor sht_exception_count = 0 humidity_exception_count = 0 @@ -1214,15 +1429,14 @@ def doMainLoop(): dewpoint_exception_count = 0 humidity_abs_exception_count = 0 - #sensortype = int(pi_ager_init.sensortype) sensordata = [] second_sensor_temperature = None second_sensor_humidity = None second_sensor_dewpoint = None second_sensor_humidity_abs = None - sensortype = cl_fact_main_sensor_type.get_instance().get_sensor_type() - sensordata = get_sensordata(sht_exception_count, humidity_exception_count, temperature_exception_count, dewpoint_exception_count, humidity_abs_exception_count, sensordata_exception_count) + sensordata = get_sensordata() + # cabinet simulation sensor_temperature = sensordata['sensor_temperature'] sensor_humidity = sensordata['sensor_humidity'] sensor_dewpoint = sensordata['sensor_dewpoint'] @@ -1246,9 +1460,11 @@ def doMainLoop(): # Prüfen, ob Sensordaten empfangen wurden und falls nicht, auf Notfallmodus wechseln if sensor_temperature != None and sensor_humidity != None and sensor_dewpoint != None: count_continuing_emergency_loops = 0 + #weitere Settings modus = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.modus_key) - setpoint_temperature = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.setpoint_temperature_key)) + + setpoint_temperature = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.setpoint_temperature_key) setpoint_humidity = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.setpoint_humidity_key)) circulation_air_period_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.circulation_air_period_key)) @@ -1258,29 +1474,40 @@ def doMainLoop(): exhaust_air_duration_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.exhaust_air_duration_key)) defrost_cycle_seconds_temp = int(pi_ager_database.get_table_value_from_field(pi_ager_names.defrost_table, pi_ager_names.defrost_cycle_hours_field)) * 3600 - switch_on_cooling_compressor = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_cooling_compressor_key)) - switch_off_cooling_compressor = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_off_cooling_compressor_key)) - switch_on_humidifier = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_humidifier_key)) - switch_off_humidifier = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_off_humidifier_key)) - delay_humidify = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.delay_humidify_key)) - delay_humidify = delay_humidify * 60 - + cooling_hysteresis = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.cooling_hysteresis_key) + heating_hysteresis = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.heating_hysteresis_key) + cooling_hysteresis_offset = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.cooling_hysteresis_offset_key) + heating_hysteresis_offset = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.heating_hysteresis_offset_key) + switch_on_cooling_compressor = cooling_hysteresis/2 + switch_off_cooling_compressor = -cooling_hysteresis/2 + switch_on_heater = heating_hysteresis/2 + switch_off_heater = -heating_hysteresis/2 + + humidifier_hysteresis = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.humidifier_hysteresis_key) + dehumidifier_hysteresis = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.dehumidifier_hysteresis_key) + humidifier_hysteresis_offset = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.humidifier_hysteresis_offset_key) + dehumidifier_hysteresis_offset = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.dehumidifier_hysteresis_offset_key) + saturation_point = pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.saturation_point_key) + uv_modus_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.uv_modus_key)) - switch_on_uv_hour = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_uv_hour_key)) - switch_on_uv_minute = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_uv_minute_key)) - uv_duration_temp = float(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.uv_duration_key)) - uv_period_temp = float(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.uv_period_key)) + switch_on_uv_hour_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_uv_hour_key)) + switch_on_uv_minute_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_uv_minute_key)) + uv_duration_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.uv_duration_key)) + uv_period_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.uv_period_key)) uv_check = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.uv_check_key)) current_time = pi_ager_database.get_current_time() # check if uv settings changed - if (uv_period_temp != uv_period or uv_duration_temp != uv_duration or uv_modus_temp != uv_modus): + if (uv_period_temp != uv_period or uv_duration_temp != uv_duration or uv_modus_temp != uv_modus or switch_on_uv_hour_temp != switch_on_uv_hour or switch_on_uv_minute_temp != switch_on_uv_minute): uv_period = uv_period_temp uv_modus = uv_modus_temp uv_duration = uv_duration_temp + switch_on_uv_hour = switch_on_uv_hour_temp + switch_on_uv_minute = switch_on_uv_minute_temp pi_ager_init.uv_starttime = current_time pi_ager_init.uv_stoptime = pi_ager_init.uv_starttime + uv_duration + uv_settings_changed = True # check if exhaust_air period or duration changed if (exhaust_air_period_temp != exhaust_air_period or exhaust_air_duration_temp != exhaust_air_duration): @@ -1300,21 +1527,33 @@ def doMainLoop(): pi_ager_init.defrost_cycle_start = current_time # Timer-Timestamp aktualisiert light_modus_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.light_modus_key)) - switch_on_light_hour = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_light_hour_key)) - switch_on_light_minute = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_light_minute_key)) - light_duration_temp = float(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.light_duration_key)) - light_period_temp = float(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.light_period_key)) + switch_on_light_hour_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_light_hour_key)) + switch_on_light_minute_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.switch_on_light_minute_key)) + light_duration_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.light_duration_key)) + light_period_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.light_period_key)) # check if light settings changed - if (light_period_temp != light_period or light_duration_temp != light_duration or light_modus_temp != light_modus): + if (light_period_temp != light_period or light_duration_temp != light_duration or light_modus_temp != light_modus or switch_on_light_hour_temp != switch_on_light_hour or switch_on_light_minute_temp != switch_on_light_minute): light_period = light_period_temp light_modus = light_modus_temp light_duration = light_duration_temp + switch_on_light_hour = switch_on_light_hour_temp + switch_on_light_minute = switch_on_light_minute_temp pi_ager_init.light_starttime = current_time pi_ager_init.light_stoptime = pi_ager_init.light_starttime + light_duration + light_settings_changed = True dehumidifier_modus = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.dehumidifier_modus_key)) - + + # check if humidifier monitoring parameter changed + delay_monitoring_humidifier_changed = False + delay_monitoring_humidifier_temp = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.delay_monitoring_humidifier_key)) + if (delay_monitoring_humidifier != delay_monitoring_humidifier_temp): + delay_monitoring_humidifier = delay_monitoring_humidifier_temp + delay_monitoring_humidifier_changed = True + check_monitoring_hum = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.check_monitoring_humidifier_key)) + tolerance_monitoring_humidifier = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.tolerance_monitoring_humidifier_key)) + # An dieser Stelle sind alle settings eingelesen, Ausgabe auf Konsole logstring = ' \n ' + pi_ager_names.logspacer @@ -1326,11 +1565,11 @@ def doMainLoop(): logstring = logstring + ' \n ' + _('target temperature') + ': ' + str(setpoint_temperature) + ' °C' #cl_fact_logger.get_instance().debug(logstring) - logstring = logstring + ' \n ' + _('actual temperature') + ': ' + str(sensor_temperature) + ' °C' + logstring = logstring + ' \n ' + _('actual temperature') + ': ' + f'{sensor_temperature:.2f}' + ' °C' #cl_fact_logger.get_instance().debug(logstring) logstring = logstring + ' \n ' + pi_ager_names.logspacer2 logstring = logstring + ' \n ' + _('target humidity') + ': ' + str(setpoint_humidity) + ' %' - logstring = logstring + ' \n ' + _('actual humidity') + ': ' + str(sensor_humidity) + ' %' + logstring = logstring + ' \n ' + _('actual humidity') + ': ' + f'{sensor_humidity:.1f}' + ' %' #cl_fact_logger.get_instance().debug(logstring) logstring = logstring + ' \n ' + _('actual dewpoint') + ': ' + str(sensor_dewpoint) + ' °C' logstring = logstring + ' \n ' + _('actual humidity abs') + ': ' + str(sensor_humidity_abs) + ' g/m³' @@ -1344,10 +1583,6 @@ def doMainLoop(): logstring = logstring + ' \n ' + _('actual humidity abs') + ': ' + str(second_sensor_humidity_abs) + ' g/m³' logstring = logstring + ' \n ' + pi_ager_names.logspacer2 - #cl_fact_logger.get_instance().debug(_('value in database') + ': ' + str(sensortype)) - # logger.info(pi_ager_names.logspacer2) - - # gpio.setmode(pi_ager_names.board_mode) # Durch den folgenden Timer laeuft der Ventilator in den vorgegebenen Intervallen zusaetzlich zur generellen Umluft bei aktivem Heizen, Kuehlen oder Befeuchten # Timer fuer Luftumwaelzung-Ventilator @@ -1443,11 +1678,13 @@ def doMainLoop(): year_now = now.year month_now = now.month day_now = now.day + + if (uv_settings_changed == True): + pi_ager_init.uv_starttime = datetime.datetime(year_now, month_now, day_now, switch_on_uv_hour, switch_on_uv_minute, 0, 0).timestamp() + pi_ager_init.uv_stoptime = pi_ager_init.uv_starttime + uv_duration + uv_settings_changed = False - pi_ager_init.uv_starttime = datetime.datetime(year_now, month_now, day_now, switch_on_uv_hour, switch_on_uv_minute, 0, 0) - pi_ager_init.uv_stoptime = pi_ager_init.uv_starttime + datetime.timedelta(0, uv_duration) - - if now >= pi_ager_init.uv_starttime and now <= pi_ager_init.uv_stoptime: + if current_time >= pi_ager_init.uv_starttime and current_time <= pi_ager_init.uv_stoptime: status_uv = True # UV-Licht an logstring = logstring + ' \n ' + _('uv-light timestamp active') + ' (' + _('uv-light on') +')' # cl_fact_logger.get_instance().debug(logstring) @@ -1455,7 +1692,11 @@ def doMainLoop(): status_uv = False # UV-Licht aus logstring = logstring + ' \n ' + _('uv-light timestamp active') + ' (' + _('uv-light off') +')' # cl_fact_logger.get_instance().debug(logstring) - + + if (current_time > pi_ager_init.uv_stoptime): # begin a new cycle + pi_ager_init.uv_starttime = datetime.datetime(year_now, month_now, day_now, switch_on_uv_hour, switch_on_uv_minute, 0, 0).timestamp() + pi_ager_init.uv_stoptime = pi_ager_init.uv_starttime + uv_duration + # Timer fuer Licht if light_modus == 0: # Modus 0 Licht aus status_light = False # Licht aus @@ -1511,10 +1752,12 @@ def doMainLoop(): month_now = now.month day_now = now.day - pi_ager_init.light_starttime = datetime.datetime(year_now, month_now, day_now, switch_on_light_hour, switch_on_light_minute, 0, 0) - pi_ager_init.light_stoptime = pi_ager_init.light_starttime + datetime.timedelta(0, light_duration) + if (light_settings_changed == True): + pi_ager_init.light_starttime = datetime.datetime(year_now, month_now, day_now, switch_on_light_hour, switch_on_light_minute, 0, 0).timestamp() + pi_ager_init.light_stoptime = pi_ager_init.light_starttime + light_duration + light_settings_changed = False - if now >= pi_ager_init.light_starttime and now <= pi_ager_init.light_stoptime: + if current_time >= pi_ager_init.light_starttime and current_time <= pi_ager_init.light_stoptime: status_light = True # Licht an logstring = logstring + ' \n ' + _('light timestamp active') + ' (' + _('light on') +')' # cl_fact_logger.get_instance().debug(logstring) @@ -1523,6 +1766,10 @@ def doMainLoop(): logstring = logstring + ' \n ' + _('light timestamp active') + ' (' + _('light off') +')' # cl_fact_logger.get_instance().debug(logstring) + if (current_time > pi_ager_init.light_stoptime): # begin a new cycle + pi_ager_init.light_starttime = datetime.datetime(year_now, month_now, day_now, switch_on_light_hour, switch_on_light_minute, 0, 0).timestamp() + pi_ager_init.light_stoptime = pi_ager_init.light_starttime + light_duration + # timer for defrost if current_time >= pi_ager_init.defrost_cycle_start + defrost_cycle_seconds: pi_ager_init.defrost_cycle_start = current_time # Timer-Timestamp aktualisiert @@ -1541,16 +1788,12 @@ def doMainLoop(): # turn off states possibly set by other modes status_exhaust_fan = False # Feuchtereduzierung Abluft aus status_dehumidifier = False # Entfeuchter aus - # gpio.output(pi_ager_gpio_config.gpio_heater, pi_ager_names.relay_off) # Heizung aus + status_humidifier = False # Befeuchter aus control_heater(pi_ager_names.relay_off) - gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_off) # Befeuchtung aus + # gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_off) # Befeuchtung aus - # check if cooler must be set on or off - if sensor_temperature >= setpoint_temperature + switch_on_cooling_compressor: - delay_cooling_compressor( pi_ager_names.relay_on) # Kuehlung ein - if sensor_temperature <= setpoint_temperature + switch_off_cooling_compressor: - delay_cooling_compressor( pi_ager_names.relay_off) # Kuehlung aus - + simple_cooler_temperature_control() + # Kuehlen mit Befeuchtung if modus == 1: # turn off states possibly set by other modes @@ -1558,23 +1801,11 @@ def doMainLoop(): status_dehumidifier = False # Entfeuchter aus # gpio.output(pi_ager_gpio_config.gpio_heater, pi_ager_names.relay_off) # Heizung aus control_heater(pi_ager_names.relay_off) - # check if cooler must be set on or off - if sensor_temperature >= setpoint_temperature + switch_on_cooling_compressor: - delay_cooling_compressor( pi_ager_names.relay_on) # Kuehlung ein - if sensor_temperature <= setpoint_temperature + switch_off_cooling_compressor : - delay_cooling_compressor( pi_ager_names.relay_off) # Kuehlung aus - - # check if humidifier must be set on or off - if sensor_humidity <= setpoint_humidity - switch_on_humidifier: - # check if delay time passed - if not humidify_delay_switch: - humidify_delay_switch = True - humidify_delay_starttime = pi_ager_database.get_current_time() - if pi_ager_database.get_current_time() >= humidify_delay_starttime + delay_humidify: # Verzoegerung der Luftbefeuchtung - gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_on) # Luftbefeuchter ein - if sensor_humidity >= setpoint_humidity - switch_off_humidifier: - gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_off) # Luftbefeuchter aus - humidify_delay_switch = False + + simple_cooler_temperature_control() + + # check if humidifier must be set on or off + simple_humidity_control() # Heizen mit Befeuchtung if modus == 2: @@ -1582,26 +1813,11 @@ def doMainLoop(): status_exhaust_fan = False # Feuchtereduzierung Abluft aus status_dehumidifier = False # Entfeuchter aus delay_cooling_compressor( pi_ager_names.relay_off) # Kuehlung aus + + simple_heater_temperature_control() - # check if heater must be set on or off - if sensor_temperature <= setpoint_temperature - switch_on_cooling_compressor: - #gpio.output(pi_ager_gpio_config.gpio_heater, pi_ager_names.relay_on) # Heizung ein - control_heater(pi_ager_names.relay_on) - if sensor_temperature >= setpoint_temperature - switch_off_cooling_compressor: - #gpio.output(pi_ager_gpio_config.gpio_heater, pi_ager_names.relay_off) # Heizung aus - control_heater(pi_ager_names.relay_off) - # check if humidifier must be set on or off - if sensor_humidity <= setpoint_humidity - switch_on_humidifier: - # check if delay time passed - if not humidify_delay_switch: - humidify_delay_switch = True - humidify_delay_starttime = pi_ager_database.get_current_time() - if pi_ager_database.get_current_time() >= humidify_delay_starttime + delay_humidify: # Verzoegerung der Luftbefeuchtung - gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_on) # Luftbefeuchter ein - if sensor_humidity >= setpoint_humidity - switch_off_humidifier: - gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_off) # Luftbefeuchter aus - humidify_delay_switch = False + simple_humidity_control() # Automatiktemperatur mit Befeuchtung if modus == 3: @@ -1609,94 +1825,66 @@ def doMainLoop(): status_exhaust_fan = False # Feuchtereduzierung Abluft aus status_dehumidifier = False # Entfeuchter aus - # check if cooler must be set on or off - if sensor_temperature >= setpoint_temperature + switch_on_cooling_compressor: - delay_cooling_compressor( pi_ager_names.relay_on) # Kuehlung ein - if sensor_temperature <= setpoint_temperature + switch_off_cooling_compressor: - delay_cooling_compressor( pi_ager_names.relay_off) # Kuehlung aus - - # check if heater must be set on or off - if sensor_temperature <= setpoint_temperature - switch_on_cooling_compressor: - #gpio.output(pi_ager_gpio_config.gpio_heater, pi_ager_names.relay_on) # Heizung ein - control_heater(pi_ager_names.relay_on) - - if sensor_temperature >= setpoint_temperature - switch_off_cooling_compressor: - #gpio.output(pi_ager_gpio_config.gpio_heater, pi_ager_names.relay_off) # Heizung aus - control_heater(pi_ager_names.relay_off) - + auto_temperature_control() + # check if humidifier must be set on or off - if sensor_humidity <= setpoint_humidity - switch_on_humidifier: - if not humidify_delay_switch: - humidify_delay_switch = True - humidify_delay_starttime = pi_ager_database.get_current_time() - if pi_ager_database.get_current_time() >= humidify_delay_starttime + delay_humidify: # Verzoegerung der Luftbefeuchtung - gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_on) # Luftbefeuchter ein - if sensor_humidity >= setpoint_humidity - switch_off_humidifier: - gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_off) # Luftbefeuchter aus - humidify_delay_switch = False + simple_humidity_control() # Automatik mit Befeuchtung und Entfeuchtung durch (Abluft-)Luftaustausch if modus == 4: # Wenn in der toten Zone der Hysterese, nehmen wir den alten Wert - status_dehumidifier = not gpio.input(pi_ager_gpio_config.gpio_dehumidifier) # Entfeuchter alter Wert - status_exhaust_fan = not gpio.input(pi_ager_gpio_config.gpio_exhausting_air) # Abluft alter Wert + # status_dehumidifier = not gpio.input(pi_ager_gpio_config.gpio_dehumidifier) # Entfeuchter alter Wert + # status_exhaust_fan = not gpio.input(pi_ager_gpio_config.gpio_exhausting_air) # Abluft alter Wert - # check if cooler or heater must be set on or off - if sensor_temperature >= setpoint_temperature + switch_on_cooling_compressor: - delay_cooling_compressor( pi_ager_names.relay_on) # Kuehlung ein - if sensor_temperature <= setpoint_temperature - switch_on_cooling_compressor: - #gpio.output(pi_ager_gpio_config.gpio_heater, pi_ager_names.relay_on) # Heizung ein - control_heater(pi_ager_names.relay_on) - - if sensor_temperature <= setpoint_temperature + switch_off_cooling_compressor: - delay_cooling_compressor( pi_ager_names.relay_off) # Kuehlung aus - if sensor_temperature >= setpoint_temperature - switch_off_cooling_compressor: - #gpio.output(pi_ager_gpio_config.gpio_heater, pi_ager_names.relay_off) # Heizung aus - control_heater(pi_ager_names.relay_off) - - # check if humidifier must be set on or off - if sensor_humidity <= setpoint_humidity - switch_on_humidifier: - if not humidify_delay_switch: - humidify_delay_switch = True - humidify_delay_starttime = pi_ager_database.get_current_time() - if pi_ager_database.get_current_time() >= humidify_delay_starttime + delay_humidify: # Verzoegerung der Luftbefeuchtung - gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_on) # Luftbefeuchter ein - if sensor_humidity >= setpoint_humidity - switch_off_humidifier: - gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_off) # Luftbefeuchter aus - humidify_delay_switch = False + auto_temperature_control() - # cl_fact_logger.get_instance().debug(_('Sensor humidity =') + str(sensor_humidity)) - # cl_fact_logger.get_instance().debug(_('Setpoint humidity =') + str(setpoint_humidity)) - # cl_fact_logger.get_instance().debug(_('Switch on humidifier =') + str(switch_on_humidifier)) + # check if humidifier must be set on or off + simple_humidity_control() - # check if humidity too high => dehumifify - if sensor_humidity >= setpoint_humidity + switch_on_humidifier: - # cl_fact_logger.get_instance().debug('sensor_humidity >= setpoint_humidity + switch_on_humidifier:') - # cl_fact_logger.get_instance().debug('Dehumidifier modus =' + ': ' + str(dehumidifier_modus)) + # check if humidity too high => dehumidify + humidity_high = eval_switch_on_dehumidity( setpoint_humidity, dehumidifier_hysteresis, dehumidifier_hysteresis_offset, saturation_point ) + if sensor_humidity >= humidity_high: if dehumidifier_modus == 1 or dehumidifier_modus == 2: # entweder nur über Abluft oder Abluft mit Unterstützung von Entfeuchter - # cl_fact_logger.get_instance().debug(_('Dehumidifier Modus 1 or 2: Status Exhaust fan = On')) status_exhaust_fan = True # Feuchtereduzierung Abluft-Ventilator ein if dehumidifier_modus == 2: # Entfeuchter zur Unterstützung - # cl_fact_logger.get_instance().debug(_('Status Dehumidifier = On')) status_dehumidifier = True # Entfeuchter unterstützend ein else: - # cl_fact_logger.get_instance().debug(_('Status Dehumidifier = Off')) status_dehumidifier = False # Entfeuchter aus - if dehumidifier_modus == 3: # rein über entfeuchtung + else: # rein über entfeuchtung status_exhaust_fan = False # Abluft aus status_dehumidifier = True # Entfeuchter ein - # cl_fact_logger.get_instance().debug(_('Dehumidifier modus 3: Status Exhaust fan = Off, Status Dehumidifier = On')) - - if sensor_humidity <= setpoint_humidity + switch_off_humidifier: - cl_fact_logger.get_instance().debug('sensor_humidity <= setpoint_humidity + switch_off_humidifier') + # cl_fact_logger.get_instance().info("Mode 4: sensor_humidity = " + f'{sensor_humidity:.1f}' + ' %' + ". humidity_high = " + f'{humidity_high:.1f}') + + humidity_low = eval_switch_off_dehumidity( setpoint_humidity, dehumidifier_hysteresis, dehumidifier_hysteresis_offset ) + if sensor_humidity <= humidity_low: if dehumidifier_modus == 1 or dehumidifier_modus == 2: status_exhaust_fan = False # Feuchtereduzierung Abluft-Ventilator aus status_dehumidifier = False # Entfeuchter aus else: status_dehumidifier = False # Entfeuchter aus + # cl_fact_logger.get_instance().info("Mode 4: sensor_humidity = " + f'{sensor_humidity:.1f}' + ' %' + ". humidity_low = " + f'{humidity_low:.1f}') + # cl_fact_logger.get_instance().info("Mode 4: status_dehumidifier = " + str(status_dehumidifier) + ". status_humidifier = " + str(status_humidifier)) - + block_humidifier = generate_humidifier_block( modus ) # evaluate if humidifier must be blocked every measure cycle + if (status_humidifier == True and block_humidifier == True): # block humudifier + status_humidifier = False + # cl_fact_logger.get_instance().debug("Humidifier blocked by cooler active and during additional delay time.") + + # Schalten des Entfeuchters und Befeuchters + if (status_humidifier == False and status_dehumidifier == False) : + gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_off) + gpio.output(pi_ager_gpio_config.gpio_dehumidifier, pi_ager_names.relay_off) + elif (status_humidifier == False and status_dehumidifier == True) : + gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_off) + gpio.output(pi_ager_gpio_config.gpio_dehumidifier, pi_ager_names.relay_on) + elif (status_humidifier == True and status_dehumidifier == False) : + gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_on) + gpio.output(pi_ager_gpio_config.gpio_dehumidifier, pi_ager_names.relay_off) + else: + gpio.output(pi_ager_gpio_config.gpio_humidifier, pi_ager_names.relay_on) + gpio.output(pi_ager_gpio_config.gpio_dehumidifier, pi_ager_names.relay_off) + # Schalten des UV_Licht if status_uv == True and pi_ager_database.get_status_uv_manual() == 1: switch_uv_light(pi_ager_names.relay_on) @@ -1717,7 +1905,6 @@ def doMainLoop(): # gpio.output(pi_ager_names.gpio_light, pi_ager_names.relay_off) # turn on circulation air when uv_check is true and UV-Light is ON - if (gpio.input(pi_ager_gpio_config.gpio_uv) == False and uv_check == True): status_circulating_air = True @@ -1729,13 +1916,7 @@ def doMainLoop(): else: # if gpio.input(pi_ager_gpio_config.gpio_heater) and gpio.input(pi_ager_gpio_config.gpio_cooling_compressor) and gpio.input(pi_ager_gpio_config.gpio_humidifier) and status_circulating_air == False: # gpio.output(pi_ager_gpio_config.gpio_circulating_air, pi_ager_names.relay_off) # Umluft - Ventilator aus control_circulating_air( pi_ager_names.relay_off ) - - # Schalten des Entfeuchters - if status_dehumidifier == True: - gpio.output(pi_ager_gpio_config.gpio_dehumidifier, pi_ager_names.relay_on) - else: - gpio.output(pi_ager_gpio_config.gpio_dehumidifier, pi_ager_names.relay_off) - + # Schalten des (Abluft-)Luftaustausch-Ventilator # Einschalten immer, wenn der status_exhaust_air_timer true ist. Der status_exhaust_fan wird # verknüpft mit check_int_ext_humidity, d.h.wenn externe abs. Feuchte höher ist als interne abs. Feuchte und @@ -1747,6 +1928,7 @@ def doMainLoop(): # verknüpfe check_int_ext_humidity mit status_exhaust_fan aus der Regelung check_result = check_int_ext_humidity() + # cl_fact_logger.get_instance().info("check_result = " + str(check_result) + ". status_exhaust_fan = " + str(status_exhaust_fan) + ". status_exhaust_air_timer = " + str(status_exhaust_air_timer)) status_exhaust_fan = status_exhaust_fan and not check_result if (status_exhaust_air_timer == True or status_exhaust_fan == True): @@ -1801,7 +1983,7 @@ def doMainLoop(): else: logstring = logstring + ' \n ' + _('weight scale') + ' 2: ' + str(round(scale2_data)) + ' g' - (log_changed, log, log_html) = status_value_has_changed() + (log_changed, log, log_html) = status_value_has_changed() # check if relais outputs have changed log_html = logstring + ' \n ' + log_html + '\n' + pi_ager_names.logspacer2 + '\n' log_event = logstring + ' \n ' + log + '\n' + pi_ager_names.logspacer2 + '\n' @@ -1814,22 +1996,55 @@ def doMainLoop(): # check on cooler failure generate_cooler_failure_events() - # Messwerte in die RRD-Datei schreiben - # Schreiben der aktuellen Status-Werte + # Messwerte in die all_sensors DB Tabelle schreiben + # Schreiben der aktuellen Werte in die current_values DB Tabelle pi_ager_database.write_current(sensor_temperature, status_heater, status_exhaust_air, status_cooling_compressor, status_circulating_air, sensor_humidity, sensor_dewpoint, sensor_humidity_abs, second_sensor_temperature, second_sensor_humidity, second_sensor_dewpoint, second_sensor_humidity_abs, status_uv, status_light, status_humidifier, status_dehumidifier, temp_sensor1_data, temp_sensor2_data, temp_sensor3_data, temp_sensor4_data) - pi_ager_database.write_all_sensordata(pi_ager_init.loopcounter, sensor_temperature, sensor_humidity, sensor_dewpoint, second_sensor_temperature, second_sensor_humidity, second_sensor_dewpoint, temp_sensor1_data, temp_sensor2_data, temp_sensor3_data, temp_sensor4_data, sensor_humidity_abs, second_sensor_humidity_abs) - cl_fact_logger.get_instance().debug('writing current values in database performed') + cl_fact_logger.get_instance().debug('writing current values into database performed') + save_loop = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.save_temperature_humidity_loops_key)) + if (pi_ager_init.loopcounter % save_loop) == 0: # schreibt Daten für die Diagramme alle n Loops in die DB, measurement loop von 10s auf 5s verkürzt + # evaluate average for temperature and humidity + average_data_temp.insert_value(sensor_temperature) + average_data_hum.insert_value(sensor_humidity) + temp_avg = average_data_temp.eval_average() + hum_avg = average_data_hum.eval_average() + hum_abs_avg = calc_humidity_abs(temp_avg, hum_avg) + temperature_avg = int((temp_avg * 100) + 0.5) / 100. + humidity_avg = int((hum_avg * 100) + 0.5) / 100.0 + humidity_abs_avg = int((hum_abs_avg * 100) + 0.5) / 100.0 + pi_ager_database.write_current_value(pi_ager_names.temperature_avg_key, temperature_avg) + pi_ager_database.write_current_value(pi_ager_names.humidity_avg_key, humidity_avg) + pi_ager_database.write_current_value(pi_ager_names.humidity_abs_avg_key, humidity_abs_avg) + + # cl_fact_logger.get_instance().info(f'Average temperature : {temperature_avg:.2f} Average humidity : {humidity_avg:.2f} Average humidity abs. : {humidity_abs_avg:.2f}') + # cl_fact_logger.get_instance().info('Size average temperature FIFO : ' + str(average_data_temp.eval_fifo_len())) + pi_ager_database.write_all_sensordata(sensor_temperature, sensor_humidity, sensor_dewpoint, second_sensor_temperature, second_sensor_humidity, second_sensor_dewpoint, temp_sensor1_data, temp_sensor2_data, temp_sensor3_data, temp_sensor4_data, sensor_humidity_abs, second_sensor_humidity_abs, temperature_avg, humidity_avg) + cl_fact_logger.get_instance().debug('writing values into all_sensors database table performed') + cl_fact_logger.get_instance().debug('checking internal temperature sensor limits') + check_internal_temperature_limits( temperature_avg ) + # check if events should be issued - cl_fact_logger.get_instance().debug('checking internal temperature sensor limits') - check_internal_temperature_limits() cl_fact_logger.get_instance().debug('checking UPS state') generate_ups_bat_events() cl_fact_logger.get_instance().debug('checking power monitor') generate_power_monitor_events() cl_fact_logger.get_instance().debug('checking switch') - generate_switch_event() - + generate_switch_event() + cl_fact_logger.get_instance().debug('checking humidifier failure') + check_monitoring_humidifier(hum_avg, setpoint_humidity, delay_monitoring_humidifier, delay_monitoring_humidifier_changed, modus, tolerance_monitoring_humidifier, check_monitoring_hum) + # cabinet simulation + # if (second_sensor_humidity == None or second_sensor_humidity > sensor_humidity): + # sensor_humidity += 0.04 + # cl_fact_logger.get_instance().info("Incremented humidity = " + f'{sensor_humidity:.1f}' + ' %') + # else: + # sensor_humidity -= 0.04 + # cl_fact_logger.get_instance().info("Decremented humidity = " + f'{sensor_humidity:.1f}' + ' %') + +# if (second_sensor_temperature == None or second_sensor_temperature > sensor_temperature): +# sensor_temperature += 0.005 # simulate increasing cabinet temperature over time +# else: +# sensor_temperature -= 0.005 # simulate decreasing cabinet temperature over time + else: count_continuing_emergency_loops += 1 # logger.debug('loopnumber: ' + str(pi_ager_init.loopcounter) + ' without sensordata!!') @@ -1861,9 +2076,10 @@ def doMainLoop(): # Ende While-Schleife cl_fact_logger.get_instance().debug('status != 1 or shutdown') -# pi_ager_gpio_config.defaultGPIO() - + # reflect i/o status in DB + switch_light(pi_ager_names.relay_off) + switch_uv_light(pi_ager_names.relay_off) pi_ager_database.write_current(sensor_temperature, 0, 0, 0, 0, sensor_humidity, sensor_dewpoint, sensor_humidity_abs, second_sensor_temperature, second_sensor_humidity, second_sensor_dewpoint, second_sensor_humidity_abs, 0, 0, 0, 0, temp_sensor1_data, temp_sensor2_data, temp_sensor3_data, temp_sensor4_data) cl_fact_logger.get_instance().debug('in loop try end -----------------------------------------------------') @@ -1873,9 +2089,6 @@ def doMainLoop(): finally: cl_fact_logger.get_instance().debug('in loop finally-----------------------------------------------------') - if (cooling_Delay_timer_running): - cooling_Delay_timer.cancel() - pi_ager_gpio_config.defaultGPIO() # reflect i/o status in DB # pi_ager_database.write_current(sensor_temperature, 0, 0, 0, 0, sensor_humidity, sensor_dewpoint, sensor_humidity_abs, second_sensor_temperature, second_sensor_humidity, second_sensor_dewpoint, second_sensor_humidity_abs, 0, 0, 0, 0, temp_sensor1_data, temp_sensor2_data, temp_sensor3_data, temp_sensor4_data) \ No newline at end of file diff --git a/opt/pi-ager/pi_ager_names.py b/opt/pi-ager/pi_ager_names.py index f3c349751..59cfa348d 100644 --- a/opt/pi-ager/pi_ager_names.py +++ b/opt/pi-ager/pi_ager_names.py @@ -8,7 +8,7 @@ #import RPi.GPIO as gpio ########################### Definition of variables -version_number = '3.3.3' +version_number = '4.0.0' # tables names config_settings_table = 'config' @@ -34,13 +34,15 @@ atc_mi_thermometer_data_table = 'atc_mi_thermometer_data' defrost_table = 'config_defrost' config_current_check_table = 'config_current_check' +time_meter_table = 'time_meter' +config_mqtt_table = 'config_mqtt' +humidity_offset_table = 'humidity_offset' # table keys -switch_on_cooling_compressor_key = 'switch_on_cooling_compressor' -switch_off_cooling_compressor_key = 'switch_off_cooling_compressor' -switch_on_humidifier_key = 'switch_on_humidifier' -switch_off_humidifier_key = 'switch_off_humidifier' +cooling_hysteresis_key = 'cooling_hysteresis' +heating_hysteresis_key = 'heating_hysteresis' delay_humidify_key = 'delay_humidify' +saturation_point_key = 'saturation_point' delay_cooler_key = 'delay_cooler' diagram_modus_key = 'diagram_modus' referenceunit_scale1_key = 'referenceunit_scale1' @@ -115,7 +117,7 @@ agingtable_period_starttime_key = 'agingtable_period_starttime' customtime_for_diagrams_key = 'customtime_for_diagrams' measuring_interval_debug_key = 'measuring_interval_debug' -agingtable_days_in_seconds_debug_key = 'agingtable_days_in_seconds_debug' +agingtable_hours_in_seconds_debug_key = 'agingtable_hours_in_seconds_debug' measuring_duration_key = 'measuring_duration' samples_refunit_tara_key = 'samples_refunit_tara' spikes_refunit_tara_key = 'spikes_refunit_tara' @@ -123,8 +125,8 @@ failure_temperature_delta_key = 'failure_temperature_delta' failure_humidity_delta_key = 'failure_humidity_delta' failure_dewpoint_delta_key = 'failure_dewpoint_delta' -agingtable_period_day_key = 'agingtable_period_day' -agingtable_startday_key = 'agingtable_startday' +agingtable_period_hour_key = 'agingtable_period_hour' +agingtable_starthour_key = 'agingtable_starthour' agingtable_startperiod_key = 'agingtable_startperiod' aging_thread_alive_key = 'aging_thread_alive' scale1_thread_alive_key = 'scale1_thread_alive' @@ -158,6 +160,24 @@ status_defrost_key = 'status_defrost' uv_check_key = 'uv_check' +temperature_avg_key = 'temperature_avg' +humidity_avg_key = 'humidity_avg' +humidity_abs_avg_key = 'humidity_abs_avg' +temp_avg_maxlen_key = 'temp_avg_maxlen' +hum_avg_maxlen_key = 'hum_avg_maxlen' + +humidifier_hysteresis_key = 'humidifier_hysteresis' +dehumidifier_hysteresis_key = 'dehumidifier_hysteresis' +humidifier_hysteresis_offset_key = 'humidifier_hysteresis_offset' +dehumidifier_hysteresis_offset_key = 'dehumidifier_hysteresis_offset' + +delay_monitoring_humidifier_key = 'delay_monitoring_humidifier' +tolerance_monitoring_humidifier_key = 'tolerance_monitoring_humidifier' +check_monitoring_humidifier_key = 'check_monitoring_humidifier' + +cooling_hysteresis_offset_key = 'cooling_hysteresis_offset' +heating_hysteresis_offset_key = 'heating_hysteresis_offset' + # table fields key_field = 'key' value_field = 'value' @@ -171,7 +191,7 @@ agingtable_circulation_air_period_field = 'circulation_air_period' agingtable_exhaust_air_duration_field = 'exhaust_air_duration' agingtable_exhaust_air_period_field = 'exhaust_air_period' -agingtable_days_field = 'days' +agingtable_hours_field = 'hours' agingtable_comment_field = 'comment' meat_sensortypes_name_field = 'name' meat_sensortypes_a_field = 'a' @@ -205,11 +225,22 @@ current_check_active_field = 'current_check_active' current_threshold_field = 'current_threshold' repeat_event_cycle_field = 'repeat_event_cycle' +uv_light_seconds_field = 'uv_light_seconds' +pi_ager_seconds_field = 'pi_ager_seconds' +defrost_temp_limit_field = 'temp_limit' +defrost_circulate_air_field = 'circulate_air' +tempintavg_field = 'tempintavg' +humintavg_field = 'humintavg' +broker_address_field = 'broker_address' +port_field = 'port' +username_field = 'username' +password_field = 'password' +mqtt_active_field = 'mqtt_active' # Paths and urls -thread_url = 'https://www.grillsportverein.de/forum/threads/pi-ager-reifeschranksteuerung-mittels-raspberry-pi.273805/' +thread_url = 'https://www.grillsportverein.de/forum/threads/pi-ager-reifeschranksteuerung-mittels-raspberry-pi-release-3-3-x.342426/' error_reporting_url = 'https://github.com/Tronje-the-Falconer/Pi-Ager/wiki/Error-reporting' -faq_url = 'https://github.com/Tronje-the-Falconer/Pi-Ager/wiki/FAQ' +faq_url = 'https://pi-ager.org/faq/' sqlite_path = '/var/www/config/pi-ager.sqlite3' logfile_txt_file = '/var/www/logs/logfile.txt' pi_ager_log_file = '/var/www/logs/pi-ager.log' @@ -233,278 +264,49 @@ relay_on = pin_without_voltage # negative Logik!!! des Relay's, Schaltet bei 0 | GPIO.LOW | False ein relay_off = (not relay_on) # negative Logik!!! des Relay's, Schaltet bei 1 | GPIO.High | True aus -logspacer = "*****************************************" -logspacer2 = '-----------------------------------------' - -######################################### DATABASE-CHECK - -# field types -field_type = {} -field_type[key_field] = 'TEXT' -field_type[value_field] = 'REAL' -field_type[system_table + '_' + value_field] = 'TEXT' -field_type[last_change_field] = 'INTEGER' -field_type[id_field] = 'INTEGER' - -id_value_tables = [status_heater_table,status_exhaust_air_table,status_cooling_compressor_table,status_circulating_air_table, status_uv_table, status_light_table, status_humidifier_table, status_dehumidifier_table] - -key_value_tables = [current_values_table, settings_scale1_table, settings_scale2_table, config_settings_table, debug_table, system_table] - -# Arrays with defined keys in key-value-tables and default values -table_keys = {} - -table_keys[config_settings_table] = (switch_on_cooling_compressor_key,switch_off_cooling_compressor_key,switch_on_humidifier_key,switch_off_humidifier_key,delay_humidify_key, - sensortype_key,language_key,switch_on_light_hour_key,switch_on_light_minute_key,light_duration_key,light_period_key,light_modus_key, - switch_on_uv_hour_key,switch_on_uv_minute_key,uv_duration_key,uv_period_key,uv_modus_key,dehumidifier_modus_key, - circulation_air_period_key,setpoint_temperature_key,exhaust_air_duration_key,modus_key,setpoint_humidity_key,exhaust_air_period_key, - circulation_air_duration_key,agingtable_key, failure_humidity_delta_key, failure_temperature_delta_key, samples_refunit_tara_key, - spikes_refunit_tara_key, save_temperature_humidity_loops_key, sensorbus_key, - meat1_sensortype_key, meat2_sensortype_key, meat3_sensortype_key, meat4_sensortype_key, customtime_for_diagrams_key, sensorsecondtype_key, - agingtable_startperiod_key, agingtable_startday_key, tft_display_type_key, internal_temperature_low_limit_key, internal_temperature_high_limit_key, internal_temperature_hysteresis_key, - shutdown_on_batlow_key, dewpoint_check_key, humidity_check_hysteresis_key) - -table_keys[current_values_table] = (sensor_temperature_key, sensor_humidity_key, status_circulating_air_key, status_cooling_compressor_key, status_exhaust_air_key, - status_heater_key, status_light_key, status_uv_key, status_humidifier_key, status_dehumidifier_key, scale1_key, scale2_key, status_pi_ager_key, - status_agingtable_key, status_scale1_key, status_scale2_key, status_tara_scale1_key, status_tara_scale2_key, agingtable_period_key, - agingtable_period_starttime_key, status_light_manual_key, calibrate_scale1_key, calibrate_scale2_key, calibrate_weight_key, - status_uv_manual_key, temperature_meat1_key, temperature_meat2_key, temperature_meat3_key, temperature_meat4_key, sensor_dewpoint_key, second_sensor_temperature_key, - second_sensor_humidity_key, second_sensor_dewpoint_key, agingtable_period_day_key, scale1_thread_alive_key, scale2_thread_alive_key, aging_thread_alive_key, - sensor_humidity_abs_key, second_sensor_humidity_abs_key, status_humidity_check_key) - -table_keys[settings_scale1_table] = (samples_key,spikes_key,sleep_key,gain_key,bits_to_read_key,referenceunit_key,scale_measuring_interval_key,measuring_duration_key,saving_period_key,offset_scale_key) -table_keys[settings_scale2_table] = (samples_key,spikes_key,sleep_key,gain_key,bits_to_read_key,referenceunit_key,scale_measuring_interval_key,measuring_duration_key,saving_period_key,offset_scale_key) - -table_keys[debug_table] = (measuring_interval_debug_key,agingtable_days_in_seconds_debug_key,loglevel_file_key,loglevel_console_key) - -table_keys[system_table] = (pi_revision_key,pi_ager_version_key) - -default_values = {} -#default values config table -default_values[config_settings_table + '_' + sensortype_key] = 3 #SHT -default_values[config_settings_table + '_' + language_key] = 1 #Deutsch de-DE -default_values[config_settings_table + '_' + save_temperature_humidity_loops_key] = 15 - -#default values scale1_settings table -default_values[settings_scale1_table + '_' + samples_key] = 20 -default_values[settings_scale1_table + '_' + spikes_key] = 60 -default_values[settings_scale1_table + '_' + sleep_key] = 0.1 -default_values[settings_scale1_table + '_' + gain_key] = 128 -default_values[settings_scale1_table + '_' + bits_to_read_key] = 24 -default_values[settings_scale1_table + '_' + referenceunit_key] = 221.2 -default_values[settings_scale1_table + '_' + scale_measuring_interval_key] = 5 -default_values[settings_scale1_table + '_' + measuring_duration_key] = 100 -default_values[settings_scale1_table + '_' + saving_period_key] = 120 - -#default values scale2_settings table -default_values[settings_scale2_table + '_' + samples_key] = 20 -default_values[settings_scale2_table + '_' + spikes_key] = 60 -default_values[settings_scale2_table + '_' + sleep_key] = 0.1 -default_values[settings_scale2_table + '_' + gain_key] = 128 -default_values[settings_scale2_table + '_' + bits_to_read_key] = 24 -default_values[settings_scale2_table + '_' + referenceunit_key] = 221.2 -default_values[settings_scale2_table + '_' + scale_measuring_interval_key] = 5 -default_values[settings_scale2_table + '_' + measuring_duration_key] = 100 -default_values[settings_scale2_table + '_' + saving_period_key] = 120 - -#default values debug table -default_values[debug_table + '_' + measuring_interval_debug_key] = 30 -default_values[debug_table + '_' + agingtable_days_in_seconds_debug_key] = 60 -default_values[debug_table + '_' + loglevel_file_key] = 10 -default_values[debug_table + '_' + loglevel_console_key] = 20 - -#default values system table -default_values[system_table + '_' + pi_ager_version_key] = '"' + version_number + '"' - -################################# JSON Creation - -tables_dict = {} - -tables_dict['config_settings_table'] = config_settings_table -tables_dict['status_heater_table'] = status_heater_table -tables_dict['status_exhaust_air_table'] = status_exhaust_air_table -tables_dict['status_cooling_compressor_table'] = status_cooling_compressor_table -tables_dict['status_circulating_air_table'] = status_circulating_air_table -tables_dict['status_uv_table'] = status_uv_table -tables_dict['status_light_table'] = status_light_table -tables_dict['status_dehumidifier_table'] = status_dehumidifier_table -tables_dict['status_humidifier_table'] = status_humidifier_table -tables_dict['current_values_table'] = current_values_table -tables_dict['agingtables_table'] = agingtables_table -tables_dict['settings_scale1_table'] = settings_scale1_table -tables_dict['settings_scale2_table'] = settings_scale2_table -tables_dict['debug_table'] = debug_table -tables_dict['system_table'] = system_table - -table_keys_dict = {} - -table_keys_dict['switch_on_cooling_compressor_key'] = switch_on_cooling_compressor_key -table_keys_dict['switch_off_cooling_compressor_key'] = switch_off_cooling_compressor_key -table_keys_dict['switch_on_humidifier_key'] = switch_on_humidifier_key -table_keys_dict['switch_off_humidifier_key'] = switch_off_humidifier_key -table_keys_dict['delay_humidify_key'] = delay_humidify_key -table_keys_dict['referenceunit_scale1_key'] = referenceunit_scale1_key -table_keys_dict['referenceunit_scale2_key'] = referenceunit_scale2_key -table_keys_dict['sensortype_key'] = sensortype_key -table_keys_dict['language_key'] = language_key -table_keys_dict['switch_on_light_hour_key'] = switch_on_light_hour_key -table_keys_dict['switch_on_light_minute_key'] = switch_on_light_minute_key -table_keys_dict['light_duration_key'] = light_duration_key -table_keys_dict['light_period_key'] = light_period_key -table_keys_dict['light_modus_key'] = light_modus_key -table_keys_dict['switch_on_uv_hour_key'] = switch_on_uv_hour_key -table_keys_dict['switch_on_uv_minute_key'] = switch_on_uv_minute_key -table_keys_dict['uv_duration_key'] = uv_duration_key -table_keys_dict['uv_period_key'] = uv_period_key -table_keys_dict['uv_modus_key'] = uv_modus_key -table_keys_dict['dehumidifier_modus_key'] = dehumidifier_modus_key -table_keys_dict['circulation_air_period_key'] = circulation_air_period_key -table_keys_dict['setpoint_temperature_key'] = setpoint_temperature_key -table_keys_dict['exhaust_air_duration_key'] = exhaust_air_duration_key -table_keys_dict['modus_key'] = modus_key -table_keys_dict['setpoint_humidity_key'] = setpoint_humidity_key -#table_keys_dict['setpoint_dewpoint_key'] = setpoint_dewpoint_key -table_keys_dict['exhaust_air_period_key'] = exhaust_air_period_key -table_keys_dict['circulation_air_duration_key'] = circulation_air_duration_key -table_keys_dict['agingtable_key'] = agingtable_key - -table_keys_dict['sensor_temperature_key'] = sensor_temperature_key -table_keys_dict['sensor_humidity_key'] = sensor_humidity_key -table_keys_dict['sensor_dewpoint_key'] = sensor_dewpoint_key -table_keys_dict['status_pi_ager_key'] = status_pi_ager_key -table_keys_dict['status_agingtable_key'] = status_agingtable_key -table_keys_dict['status_heater_key'] = status_heater_key -table_keys_dict['status_exhaust_air_key'] = status_exhaust_air_key -table_keys_dict['status_cooling_compressor_key'] = status_cooling_compressor_key -table_keys_dict['status_circulating_air_key'] = status_circulating_air_key -table_keys_dict['status_uv_key'] = status_uv_key -table_keys_dict['status_light_key'] = status_light_key -table_keys_dict['status_dehumidifier_key'] = status_dehumidifier_key -table_keys_dict['status_humidifier_key'] = status_humidifier_key -table_keys_dict['status_scale1_key'] = status_scale1_key -table_keys_dict['status_scale2_key'] = status_scale2_key -table_keys_dict['status_tara_scale1_key'] = status_tara_scale1_key -table_keys_dict['status_tara_scale2_key'] = status_tara_scale2_key -table_keys_dict['status_light_manual_key'] = status_light_manual_key -table_keys_dict['status_uv_manual_key'] = status_uv_manual_key -table_keys_dict['scale1_key'] = scale1_key -table_keys_dict['scale2_key'] = scale2_key -table_keys_dict['samples_key'] = samples_key -table_keys_dict['spikes_key'] = spikes_key -table_keys_dict['sleep_key'] = sleep_key -table_keys_dict['gpio_data_key'] = gpio_data_key -table_keys_dict['gpio_sync_key'] = gpio_sync_key -table_keys_dict['gain_key'] = gain_key -table_keys_dict['bits_to_read_key'] = bits_to_read_key -table_keys_dict['referenceunit_key'] = referenceunit_key -table_keys_dict['scale_measuring_interval_key'] = scale_measuring_interval_key -table_keys_dict['save_temperature_humidity_loops_key'] = save_temperature_humidity_loops_key -table_keys_dict['loglevel_file_key'] = loglevel_file_key -table_keys_dict['loglevel_console_key'] = loglevel_console_key -table_keys_dict['agingtable_period_key'] = agingtable_period_key -table_keys_dict['agingtable_period_starttime_key'] = agingtable_period_starttime_key -table_keys_dict['measuring_interval_debug_key'] = measuring_interval_debug_key -table_keys_dict['agingtable_days_in_seconds_debug_key'] = agingtable_days_in_seconds_debug_key -table_keys_dict['measuring_duration_key'] = measuring_duration_key -table_keys_dict['samples_refunit_tara_key'] = samples_refunit_tara_key -table_keys_dict['spikes_refunit_tara_key'] = spikes_refunit_tara_key -table_keys_dict['saving_period_key'] = saving_period_key -table_keys_dict['failure_temperature_delta_key'] = failure_temperature_delta_key -table_keys_dict['failure_humidity_delta_key'] = failure_humidity_delta_key -table_keys_dict['pi_revision_key'] = pi_revision_key -table_keys_dict['pi_ager_version_key'] = pi_ager_version_key -table_keys_dict['calibrate_scale1_key'] = calibrate_scale1_key -table_keys_dict['calibrate_scale2_key'] = calibrate_scale2_key -table_keys_dict['calibrate_weight_key'] = calibrate_weight_key -table_keys_dict['offset_scale_key'] = offset_scale_key -table_keys_dict['temperature_meat1_key'] = temperature_meat1_key -table_keys_dict['temperature_meat2_key'] = temperature_meat2_key -table_keys_dict['temperature_meat3_key'] = temperature_meat3_key -table_keys_dict['temperature_meat4_key'] = temperature_meat4_key -table_keys_dict['meat1_sensortype_key'] = meat1_sensortype_key -table_keys_dict['meat2_sensortype_key'] = meat2_sensortype_key -table_keys_dict['meat3_sensortype_key'] = meat3_sensortype_key -table_keys_dict['meat4_sensortype_key'] = meat4_sensortype_key - -table_fields_dict = {} - -table_fields_dict['key_field'] = key_field -table_fields_dict['value_field'] = value_field -table_fields_dict['last_change_field'] = last_change_field -table_fields_dict['id_field'] = id_field -table_fields_dict['agingtable_name_field'] = agingtable_name_field -table_fields_dict['agingtable_modus_field'] = agingtable_modus_field -table_fields_dict['agingtable_setpoint_temperature_field'] = agingtable_setpoint_temperature_field -table_fields_dict['agingtable_setpoint_humidity_field'] = agingtable_setpoint_humidity_field -table_fields_dict['agingtable_circulation_air_duration_field'] = agingtable_circulation_air_duration_field -table_fields_dict['agingtable_circulation_air_period_field'] = agingtable_circulation_air_period_field -table_fields_dict['agingtable_exhaust_air_duration_field'] = agingtable_exhaust_air_duration_field -table_fields_dict['agingtable_exhaust_air_period_field'] = agingtable_exhaust_air_period_field -table_fields_dict['agingtable_days_field'] = agingtable_days_field -table_fields_dict['agingtable_comment_field'] = agingtable_comment_field -table_fields_dict['meat_sensortypes_name_field'] = meat_sensortypes_name_field -table_fields_dict['meat_sensortypes_a_field'] = meat_sensortypes_a_field -table_fields_dict['meat_sensortypes_b_field'] = meat_sensortypes_b_field -table_fields_dict['meat_sensortypes_c_field'] = meat_sensortypes_c_field -table_fields_dict['meat_sensortypes_Rn_field'] = meat_sensortypes_Rn_field -table_fields_dict['meat_sensortypes_Mode_field'] = meat_sensortypes_Mode_field -table_fields_dict['meat_sensortypes_RefVoltage_field'] = meat_sensortypes_RefVoltage_field -table_fields_dict['meat_sensortypes_Sensitivity_field'] = meat_sensortypes_Sensitivity_field -table_fields_dict['meat_sensortypes_Turns_field'] = meat_sensortypes_Turns_field -table_fields_dict['meat_sensortypes_nAverage_field'] = meat_sensortypes_nAverage_field - -path_url_dict = {} -path_url_dict['thread_url'] = thread_url -path_url_dict['error_reporting_url'] = error_reporting_url -path_url_dict['faq_url'] = faq_url -path_url_dict['sqlite_path'] = sqlite_path -path_url_dict['logfile_txt_file'] = logfile_txt_file -path_url_dict['pi_ager_log_file'] = pi_ager_log_file -path_url_dict['changelogfile'] = changelogfile - -json_keys_dict = {} -json_keys_dict['last_change_temperature_json_key'] = last_change_temperature_json_key -json_keys_dict['last_change_humidity_json_key'] = last_change_humidity_json_key -json_keys_dict['last_change_dewpoint_json_key'] = last_change_dewpoint_json_key -json_keys_dict['last_change_scale1_json_key'] = last_change_scale1_json_key -json_keys_dict['last_change_scale2_json_key'] = last_change_scale2_json_key -json_keys_dict['last_change_temperature_meat1_json_key'] = last_change_temperature_meat1_json_key -json_keys_dict['last_change_temperature_meat2_json_key'] = last_change_temperature_meat2_json_key -json_keys_dict['last_change_temperature_meat3_json_key'] = last_change_temperature_meat3_json_key -json_keys_dict['last_change_temperature_meat4_json_key'] = last_change_temperature_meat4_json_key - -hardcoded_values_dict = {} -hardcoded_values_dict['pi_ager_version'] = version_number - -global dict_for_json_creation -dict_for_json_creation = {} - -def add_to_dict_for_json_creation(dict): - """ - adding dictionary for creating jsonfile (web) - """ - global dict_for_json_creation - - for key,value in dict.items(): - dict_for_json_creation[key] = value - -def create_json_file(): - """ - creating jsonfile for website - """ - import json - global dict_for_json_creation - - add_to_dict_for_json_creation(tables_dict) - add_to_dict_for_json_creation(table_keys_dict) - add_to_dict_for_json_creation(table_fields_dict) - add_to_dict_for_json_creation(path_url_dict) - add_to_dict_for_json_creation(json_keys_dict) - add_to_dict_for_json_creation(hardcoded_values_dict) - - json_file = '/var/www/modules/names.json' - - - with open(json_file, 'w') as file: - file.write(json.dumps(dict_for_json_creation)) - - +logspacer = "****************" +logspacer2 = '--' + +SUPPORTED_MAIN_SENSOR_TYPES = {1: "DHT11", + 2: "DHT22", + 3: "SHT75", + 4: "SHT85", + 5: "SHT3x", + 6: "SHT3x-mod", + 7: "AHT1x", + 8: "AHT1x-mod", + 9: "AHT2x", + 10: "AHT30", + 11: "SHT4x-A", + 12: "SHT4x-B", + 13: "SHT4x-C"} + +SUPPORTED_SECOND_SENSOR_TYPES = { 0: "disabled", + 4: "SHT85", + 5: "SHT3x", + 6: "SHT3x-mod", + 7: "AHT1x", + 8: "AHT1x-mod", + 9: "AHT2x", + 10: "AHT30", + 11: "SHT4x-A", + 12: "SHT4x-B", + 13: "SHT4x-C", + 14: "MiThermometer"} + +I2C_SENSOR_ADDRESS = { 0: None, + 1: None, + 2: None, + 3: None, + 4: 0x44, + 5: 0x44, + 6: 0x45, + 7: 0x38, + 8: 0x39, + 9: 0x38, + 10: 0x38, + 11: 0x44, + 12: 0x45, + 13: 0x46, + 14: None } + \ No newline at end of file diff --git a/opt/pi-ager/sensors/pi_ager_cl_ab_sensor.py b/opt/pi-ager/sensors/pi_ager_cl_ab_sensor.py index b86e7b930..8c028b2d5 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_ab_sensor.py +++ b/opt/pi-ager/sensors/pi_ager_cl_ab_sensor.py @@ -2,104 +2,12 @@ """This abstract classes is for handling the main sensor(s) for the Pi-Ager.""" -__author__ = "Claus Fischer" -__copyright__ = "Copyright 2019, The Pi-Ager Project" -__credits__ = ["Claus Fischer"] -__license__ = "GPL" -__version__ = "1.0.0" -__maintainer__ = "Claus Fischer" -__email__ = "DerBurgermeister@pi-ager.org" -__status__ = "Production" - from abc import ABC, abstractmethod -import inspect - -#from pi_ager_cl_sensor_type import cl_fact_main_sensor_type -from main.pi_ager_cx_exception import * - - -class cl_ab_humidity_sensor(ABC): - __max_humidity_errors = 10 - __HUMIDITY_SENSOR_STATES = ["Valid", "Invalid"] +class cl_ab_sensor(ABC): def __init__(self): - self._current_humidity = 0 - self._old_humidity = 0 - self._state = 0 -""" - def get_current_humidity(self): - return(self._current_humidity) - - def get_old_humidiy(self): - return(self._old_humidity) - - @abstractmethod - def _read_data(self): pass - - def get_humidity_state(self): - return(cl_ab_humidity_sensor.__HUMIDITY_SENSOR_STATES[self._state]) - - def _check_humidity(self): - if abs(self._current_humidity - self._old_humidity) > 10: - self._state = 1 - else: - self._state = 0 -""" - -class cl_ab_temp_sensor(ABC): - __max_temp_errors = 10 - __TEMP_SENSOR_STATES = ["Valid", "Invalid"] - - def __init__(self): - self._current_temperature = 0 - self._old_temperature = 0 - self._state = 0 - -""" - def get_current_temperature(self): - return(self._current_temperature) - - def get_old_temperature(self): - return(self._old_temperature) - - @abstractmethod - def _read_data(self): - pass - - def get_temperature_state(self): - return(cl_ab_temp_sensor.__TEMP_SENSOR_STATES[self._state]) - - def _check_temperature(self): - if abs(self._current_temperature - self._old_temperature) > 10: - self._state = 1 - else: - self.m_state = 0 -""" -class cl_ab_sensor(cl_ab_temp_sensor, cl_ab_humidity_sensor): - def __init__(self): - pass @abstractmethod def get_dewpoint(self, temperature, humidity): pass - - @abstractmethod - def _write_to_db(self): #time_series db - pass - @abstractmethod - def execute(self): #execute measurement - pass - - @abstractmethod - def set_heading_on(self): #execute measurement - pass - - @abstractmethod - def set_heading_off(self): #execute measurement - pass - - @abstractmethod - def soft_reset(self): #execute measurement - pass - diff --git a/opt/pi-ager/sensors/pi_ager_cl_active_sensor.py b/opt/pi-ager/sensors/pi_ager_cl_active_sensor.py index c4ac87546..aee3346b6 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_active_sensor.py +++ b/opt/pi-ager/sensors/pi_ager_cl_active_sensor.py @@ -12,57 +12,38 @@ __status__ = "Production" from abc import ABC, abstractmethod -import math -import inspect +# import math +# import inspect from sensors.pi_ager_cl_sensor_fact import cl_fact_sensor from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type, cl_fact_second_sensor_type from main.pi_ager_cl_logger import cl_fact_logger -from datetime import datetime +# from datetime import datetime from main.pi_ager_cx_exception import * -from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor -from main.pi_ager_cl_database import cl_fact_db_influxdb +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor +# from main.pi_ager_cl_database import cl_fact_db_influxdb -class cl_active_main_sensor(): +class cl_active_main_sensor: def __init__(self, o_sensor_type, i_active_sensor, i_address): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self.o_sensor_type = o_sensor_type self.o_sensor = cl_fact_sensor().get_instance(i_active_sensor, i_address) - def execute(self): - self.o_sensor.execute() + def get_current_data(self): return( self.o_sensor.get_current_data() ) -class cl_active_second_sensor(): +class cl_active_second_sensor: def __init__(self, o_sensor_type, i_active_sensor, i_address): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self.o_sensor_type = o_sensor_type self.o_sensor = cl_fact_sensor().get_instance(i_active_sensor, i_address) - def execute(self): - self.o_sensor.execute() + def get_current_data(self): return( self.o_sensor.get_current_data() ) - -class th_active_sensor(): -# SUPPORTED_MAIN_SENSOR_TYPES = ["SHT75", "DHT11", "DHT22"] - NAME = 'Main_sensor' - - - def __init__(self): - - self.get_type_raise = False - self._type = "SHT75" - - def get_type(self): - if self.get_type_raise == True: - raise cx_Sensor_not_defined(self._type_ui) - return(self._type) - - class cl_fact_active_main_sensor: @@ -72,7 +53,7 @@ class cl_fact_active_main_sensor: @classmethod def get_instance(self, i_address=None): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) active_sensor = 'MAIN' if cl_fact_active_main_sensor.__o_instance is not None : @@ -85,11 +66,11 @@ def get_instance(self, i_address=None): @classmethod def set_instance(self, i_active_sensor, i_instance, i_address=None,): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_active_main_sensor.__o_instance = i_instance def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) pass class cl_fact_active_second_sensor: @@ -99,7 +80,7 @@ class cl_fact_active_second_sensor: @classmethod def get_instance(self, i_address=None): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) active_sensor = 'SECOND' if cl_fact_active_second_sensor.__o_instance is not None : return(cl_fact_active_second_sensor.__o_instance) @@ -111,11 +92,11 @@ def get_instance(self, i_address=None): @classmethod def set_instance(self, i_active_sensor, i_instance, i_address=None): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_second_sensor.__o_instance = i_instance def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) pass diff --git a/opt/pi-ager/sensors/pi_ager_cl_hx711.py b/opt/pi-ager/sensors/pi_ager_cl_hx711.py deleted file mode 100644 index 61a5ef008..000000000 --- a/opt/pi-ager/sensors/pi_ager_cl_hx711.py +++ /dev/null @@ -1,326 +0,0 @@ -# -*- coding: utf-8 -*- - -"""This class is for handling the HX711 weight measurement.""" - -__author__ = "Claus Fischer" -__copyright__ = "Copyright 2019, The Pi-Ager Project" -__credits__ = ["Claus Fischer"] -__license__ = "GPL" -__version__ = "1.0.0" -__maintainer__ = "Claus Fischer" -__email__ = "DerBurgermeister@pi-ager.org" -__status__ = "Development" - -#!/usr/bin/env python - -# HX711.py -# 2018-03-05 -# Public Domain -# copied from http://abyz.me.uk/rpi/pigpio/examples.html#Python_HX711_py - -CH_A_GAIN_64 = 0 # Channel A gain 64 -CH_A_GAIN_128 = 1 # Channel A gain 128 -CH_B_GAIN_32 = 2 # Channel B gain 32 - -DATA_CLKS = 24 -X_128_CLK = 25 -X_32_CLK = 26 -X_64_CLK = 27 - -PULSE_LEN = 15 - -# If the data line goes low after being high for at least -# this long it indicates that a new reading is available. - -TIMEOUT = ((X_64_CLK + 3) * 2 * PULSE_LEN) - -# The number of readings to skip after a mode change. - -SETTLE_READINGS = 5 - -import time - -#import pigpio # http://abyz.co.uk/rpi/pigpio/python.html -import pi_ager_pigpio as pigpio -import pi_ager_names - -class sensor: - - """ - A class to read the HX711 24-bit ADC. - """ - - def __init__(self, pi, DATA, CLOCK, mode=CH_A_GAIN_128, callback=None): - """ - Instantiate with the Pi, the data GPIO, and the clock GPIO. - - Optionally the channel and gain may be specified with the - mode parameter as follows. - - CH_A_GAIN_64 - Channel A gain 64 - CH_A_GAIN_128 - Channel A gain 128 - CH_B_GAIN_32 - Channel B gain 32 - - Optionally a callback to be called for each new reading may be - specified. The callback receives three parameters, the count, - the mode, and the reading. The count is incremented for each - new reading. - """ - self.pi = pi - self.DATA = DATA - self.CLOCK = CLOCK - self.callback = callback - - self._paused = True - self._data_level = 0 - self._clocks = 0 - - self._mode = CH_A_GAIN_128 - self._value = 0 - - self._rmode = CH_A_GAIN_128 - self._rval = 0 - self._count = 0 - - self._sent = 0 - self._data_tick = pi.get_current_tick() - self._previous_edge_long = False - self._in_wave = False - - self._skip_readings = SETTLE_READINGS - - pi.write(CLOCK, 1) # Reset the sensor. - - pi.set_mode(DATA, pigpio.INPUT) - - pi.wave_add_generic( - [pigpio.pulse(1< TIMEOUT - - if current_edge_long and not self._previous_edge_long: - - if not self._in_wave: - - self._in_wave = True - - self.pi.wave_chain( - [255, 0, self._wid, 255, 1, self._pulses, 0]) - - self._clocks = 0 - self._value = 0 - self._sent += 1 - - self._data_tick = tick - self._previous_edge_long = current_edge_long - -if __name__ == "__main__": - - import time - import pi_ager_pigpio as pigpio - #import HX711 - - def cbf(count, mode, reading): - print(count, mode, reading) - - pi = pigpio.pi() - if not pi.connected: - exit(0) - - - #gpio_scale2_data = 10 # GPIO fuer Waage2 Data - #gpio_scale2_sync = 9 # GPIO fuer Waage2 Sync - #s = HX711.sensor( - #pi, DATA=20, CLOCK=21, mode=HX711.CH_B_GAIN_32, callback=cbf) - s = sensor( - pi, DATA=pi_ager_names.gpio_scale2_data, CLOCK=pi_ager_names.gpio_scale2_sync, mode=HX711.CH_B_GAIN_32, callback=cbf) - - try: - print("start with CH_B_GAIN_32 and callback") - - time.sleep(2) - - s.set_mode(HX711.CH_A_GAIN_64) - - print("Change mode to CH_A_GAIN_64") - - time.sleep(2) - - s.set_mode(HX711.CH_A_GAIN_128) - - print("Change mode to CH_A_GAIN_128") - - time.sleep(2) - - s.pause() - - print("Pause") - - time.sleep(2) - - s.start() - - print("Start") - - time.sleep(2) - - s.set_callback(None) - - s.set_mode(HX711.CH_A_GAIN_128) - - print("Change mode to CH_A_GAIN_128") - - print("Cancel callback and read manually") - - c, mode, reading = s.get_reading() - - stop = time.time() + 3600 - - while time.time() < stop: - - count, mode, reading = s.get_reading() - - if count != c: - c = count - print("{} {} {}".format(count, mode, reading)) - - time.sleep(0.05) - - except KeyboardInterrupt: - pass - - s.pause() - - s.cancel() - - pi.stop() diff --git a/opt/pi-ager/sensors/pi_ager_cl_i2c_bus.py b/opt/pi-ager/sensors/pi_ager_cl_i2c_bus.py index ee8ceb2dd..f61d604f1 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_i2c_bus.py +++ b/opt/pi-ager/sensors/pi_ager_cl_i2c_bus.py @@ -11,11 +11,11 @@ __email__ = "DerBurgermeister@pi-ager.org" __status__ = "Development" -import inspect -import time -import smbus -import sys -import struct +# import inspect +# import time +import smbus2 +# import sys +# import struct # import pi_ager_logging from main.pi_ager_cl_logger import cl_fact_logger @@ -34,44 +34,22 @@ * add another 0 to the above baudrate for max setting, ie dtparam=i2c1_baudrate=100000 """ -# global logger -# logger = pi_ager_logging.create_logger(__name__) - -class cl_i2c_bus_logic(): - - __error_counter = 0 - __measuring_intervall = 300 +class cl_i2c_bus_logic: + _I2C_BUS_NUMBER = 3 - def __init__(self): - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if "get_instance" not in inspect.stack()[1][3]: - raise cx_direct_call(self,"Please use factory class" ) try: - self.bus1 = smbus.SMBus(3) - + self.bus1 = smbus2.SMBus(self._I2C_BUS_NUMBER) except Exception as cx_error: cl_fact_logic_messenger().get_instance().handle_exception(cx_error) + if self.bus1 is None: - raise cx_i2c_bus_error(self,"Can't get I2C Bus" ) + raise cx_i2c_bus_error("Can't get I2C Bus" ) + def get_i2c_bus(self): - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - # logger.debug(self.bus1) - cl_fact_logger.get_instance().debug(self.bus1) + cl_fact_logger.get_instance().debug("i2c object is : " + str(self.bus1) + " RPi I2C Bus number in use is : " + str(self._I2C_BUS_NUMBER)) return(self.bus1) -""" - def get_i2c_address(self): - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug('i2c address is ' + str(self._address)) - return(self._address) -""" -class th_i2c_bus_logic(): - - def __init__(self): - pass + class cl_fact_i2c_bus_logic(ABC): __o_instance = None @@ -81,8 +59,6 @@ def set_instance(self, i_instance): """ Factory method to set the i2c logic instance """ - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_i2c_bus_logic.__o_instance = i_instance @classmethod @@ -90,10 +66,9 @@ def get_instance(self): """ Factory method to get the i2c logic instance """ - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) if cl_fact_i2c_bus_logic.__o_instance is not None: return(cl_fact_i2c_bus_logic.__o_instance) + cl_fact_i2c_bus_logic.__o_instance = cl_i2c_bus_logic() return(cl_fact_i2c_bus_logic.__o_instance) @@ -101,11 +76,5 @@ def __init__(self): """ Constructor i2c logic factory """ - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - pass - - def __init__(self): - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) pass + diff --git a/opt/pi-ager/sensors/pi_ager_cl_i2c_sensor_sht.py b/opt/pi-ager/sensors/pi_ager_cl_i2c_sensor_sht.py deleted file mode 100644 index 37c1e8c20..000000000 --- a/opt/pi-ager/sensors/pi_ager_cl_i2c_sensor_sht.py +++ /dev/null @@ -1,130 +0,0 @@ -# -*- coding: utf-8 -*- - -"""This class is for the sensirion i2c sensors SHT3x and SHT85""" - -__author__ = "Claus Fischer" -__copyright__ = "Copyright 2019, The Pi-Ager Project" -__credits__ = ["Claus Fischer"] -__license__ = "GPL" -__version__ = "1.0.1" -__maintainer__ = "Claus Fischer" -__email__ = "DerBurgermeister@pi-ager.org" -__status__ = "Development" - -import inspect -import struct -import time -from main.pi_ager_cl_logger import cl_fact_logger - -from abc import ABC, abstractmethod -from main.pi_ager_cx_exception import * -from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger - -class cl_i2c_sensor_sht(ABC): - - __error_counter = 0 - __measuring_intervall = 300 - - - def __init__(self, i_active_sensor, i_i2c_bus, i_address): - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if "get_instance" not in inspect.stack()[1][3]: - raise cx_direct_call(self,"Please use factory class" ) - #self._sensor_type = o_sensor_type - cl_fact_logger.get_instance().debug('i2c address is ' + str(i_address)) - self._i2c_bus = i_i2c_bus - self._address = i_address - - def get_address(self): - return(self._address) - - def calculate_checksum(self, value): - """4.12 Checksum Calculation from an unsigned short input""" - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - # CRC - polynomial = 0x131 # //P(x)=x^8+x^5+x^4+1 = 100110001 - crc = 0xFF - - # calculates 8-Bit checksum with given polynomial - #for byteCtr in [ord(x) for x in struct.pack(">H", value)]: - for byteCtr in struct.pack(">H", value): - crc ^= byteCtr - for bit in range(8, 0, -1): - if crc & 0x80: - crc = (crc << 1) ^ polynomial - else: - crc = (crc << 1) - return crc - - """ - def i2c_start_command(self, i_msb_data, i_lsb_data): - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - #Write the sensor data - self._i2c_bus.write_byte_data(self._address, i_msb_data, i_lsb_data) - - def read_data(self): - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - #Read the sensor data - self.data0 = self._i2c_bus.read_i2c_block_data(self._address, 0x00, 6) - - return(self.data0) - """ - - - -class th_i2c_sensor_sht(): - - def __init__(self): - pass - - - -class cl_fact_i2c_sensor_sht(ABC): - __o_instance = None - __ot_instances = {} - @classmethod - def set_instance(self, i_instance): - """ - Factory method to set the i2c logic instance - """ - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - cl_fact_i2c_sensor_sht.__o_instance = i_instance - - @classmethod - def get_instance(self, i_active_sensor, i_i2c_bus, i_address): - """ - Factory method to get the i2c logic instance - """ - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug("Old i2c __ot_instances = " + str(cl_fact_i2c_sensor_sht.__ot_instances)) - - try: - cl_fact_i2c_sensor_sht.__o_instance = cl_fact_i2c_sensor_sht.__ot_instances.pop(i_active_sensor) - cl_fact_logger.get_instance().debug("i2c __ot_instance for " + i_active_sensor + " = " + str(cl_fact_i2c_sensor_sht.__o_instance) + " found ") - except KeyError: - cl_fact_logger.get_instance().debug("i2c __ot_instance for " + i_active_sensor + " not found ") - cl_fact_i2c_sensor_sht.__o_instance = None - - if cl_fact_i2c_sensor_sht.__o_instance is not None : - cl_fact_logger.get_instance().debug("i2c __ot_instance for " + i_active_sensor + " = "+ str(cl_fact_i2c_sensor_sht.__o_instance) + " Returning") - return(cl_fact_i2c_sensor_sht.__o_instance) - - cl_fact_i2c_sensor_sht.__o_instance = cl_i2c_sensor_sht(i_active_sensor, i_i2c_bus, i_address) - cl_fact_logger.get_instance().debug("i2c __ot_instance for " + i_active_sensor + " = " + str(cl_fact_i2c_sensor_sht.__o_instance) + " created" ) - line = {i_active_sensor:cl_fact_i2c_sensor_sht.__o_instance} - cl_fact_i2c_sensor_sht.__ot_instances.update(line) - cl_fact_logger.get_instance().debug("New i2c __ot_instances = " + str(cl_fact_i2c_sensor_sht.__ot_instances)) - return(cl_fact_i2c_sensor_sht.__o_instance) - - def __init__(self): - """ - Constructor i2c logic factory - """ - # logger.debug(pi_ager_logging.me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - pass - diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor.py b/opt/pi-ager/sensors/pi_ager_cl_sensor.py index cb4daccbb..9926e66e6 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_sensor.py +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor.py @@ -13,10 +13,11 @@ from abc import ABC, abstractmethod import math -import inspect - +# import inspect +import pi_ager_names +from pi_ager_database import get_table_row from main.pi_ager_cl_logger import cl_fact_logger -from datetime import datetime +# from datetime import datetime from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type #from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type, cl_fact_second_sensor_type @@ -24,61 +25,44 @@ from main.pi_ager_cx_exception import * from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor -from main.pi_ager_cl_database import cl_fact_db_influxdb +# from main.pi_ager_cl_database import cl_fact_db_influxdb class cl_sensor(cl_ab_sensor): def __init__(self, o_sensor_type): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) +# cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self._error_counter = 0 self._max_errors = 3 self.o_sensor_type = o_sensor_type - self.o_mean_temperature = 0 - self.o_temperature_sum = 0 - self.o_counter = 0 - + @abstractmethod def get_current_data(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if (self._error_counter >= self._max_errors): - self._execute_soft_reset() + pass +# cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) +# if (self._error_counter >= self._max_errors): +# self._execute_soft_reset() +# return 0, 0, 0, 0 def get_sensor_type_ui(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) +# cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) return( self.o_sensor_type.get_sensor_type_ui()) def get_sensor_type(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) +# cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) return( self.o_sensor_type._get_type() ) - - def delete_error_counter(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self._error_counter = 0 - - def check_error_counter(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - self._error_counter = self._error_counter + 1 - cl_fact_logger.get_instance().debug("Error counter: %i" % self._error_counter) - cl_fact_logger.get_instance().debug("Max errors: %i" % self._max_errors) - - if (self._error_counter >= self._max_errors): - raise cx_measurement_error(_('Too many measurement errors occurred!')) - - def calc_mean_temperature(self, temperature): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self.o_counter = self.o_counter + 1 - self.o_temperature_sum = self.o_temperature_sum + temperature - self.o_mean_temperature = self.o_temperature_sum / self.o_counter - cl_fact_logger.get_instance().debug("Mean Values counter:" + str(self.o_counter )+ "Temp: " + str(temperature) + "Mean: " + str(self.o_mean_temperature) ) - - - def get_mean_temperature(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - return(self.o_mean_temperature) + def get_humidity_offset(self): + humidity_offsets = get_table_row(pi_ager_names.humidity_offset_table, 1) + sensor_type = self.get_sensor_type_ui() + try: + humidity_offset = humidity_offsets[sensor_type] + cl_fact_logger.get_instance().debug("Sensor type = " + sensor_type + " hum. offset = " + str(humidity_offset)) + return humidity_offset + except: + return 0.0 + def get_dewpoint(self, temperature, humidity): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) +# cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) if humidity == 0: humidity = 1 if (temperature >= 0): @@ -103,111 +87,4 @@ def get_dewpoint(self, temperature, humidity): calculated_dewpoint = (self._temperature_dewpoint, self._humidity_absolute) return(calculated_dewpoint) - - def _execute_soft_reset(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - pass - - def _write_to_db(self): - """ Write the sensor data to DB""" - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if 1 == 2: - self._write_to_influxdb() - pass - def _write_to_influxdb(self): - """ Write the sensor data to time series DB""" - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - influx_db = cl_fact_db_influxdb.get_instance() - if (self._current_temperature != 0 ): - json_body = [ - { - "measurement": "Temperature", - "tags": { - "sensor": "Main_Sensor", - "sensor_type": str(self.get_sensor_type_ui()) - }, - # "time": str(datetime.now()), - "fields": { - "value": float(self._current_temperature) - } - } - ] - - cl_fact_logger.get_instance().debug(json_body) - influx_db.write_data_to_db(json_body) - - if (self._current_humidity != 0 ): - json_body = [ - { - "measurement": "relative Humidity", - "tags": { - "sensor": "Main_Sensor", - "sensor_type": str(self.get_sensor_type_ui()) - }, - # "time": str(datetime.now()), - "fields": { - "value": float(self._current_humidity) - } - } - ] - - cl_fact_logger.get_instance().debug(json_body) - influx_db.write_data_to_db(json_body) - - if (self._current_humidity != 0 ): - json_body = [ - { - "measurement": "DewPoint", - "tags": { - "sensor": "Main_Sensor", - "sensor_type": str(self.get_sensor_type_ui()) - }, - # "time": str(datetime.now()), - "fields": { - "value": float(self._temperature_dewpoint) - } - } - ] - - cl_fact_logger.get_instance().debug(json_body) - influx_db.write_data_to_db(json_body) - - if (self._humidity_absolute != 0 ): - json_body = [ - { - "measurement": "absolute Humidity", - "tags": { - "sensor": "Main_Sensor", - "sensor_type": str(self.get_sensor_type_ui()) - }, - # "time": str(datetime.now()), - "fields": { - "value": float(self._humidity_absolute) - } - } - ] - - cl_fact_logger.get_instance().debug(json_body) - influx_db.write_data_to_db(json_body) - pass - - def execute(self): - pass - - -class th_sensor(): -# SUPPORTED_MAIN_SENSOR_TYPES = ["SHT75", "DHT11", "DHT22"] - NAME = 'Main_sensor' - - - def __init__(self): - - self.get_type_raise = False - self._type = "SHT75" - - def get_type(self): - if self.get_type_raise == True: - raise cx_Sensor_not_defined(self._type_ui) - return(self._type) diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_MiThermometer.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_MiThermometer.py index 274ba3b98..ea80b2446 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_sensor_MiThermometer.py +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_MiThermometer.py @@ -12,7 +12,7 @@ class cl_sensor_MiThermometer(cl_sensor): def __init__(self, i_sensor_type, i_active_sensor): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self.o_active_sensor = i_active_sensor # MAIN or SECOND self.o_sensor_type = i_sensor_type # class to get second sensor name e.g. self.temperature = None @@ -26,17 +26,23 @@ def __init__(self, i_sensor_type, i_active_sensor): self.event_out_of_range = False def get_current_data(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - Mi_Timeout = 50 - mi_data = pi_ager_database.get_table_value_from_field(pi_ager_names.atc_mi_thermometer_data_table, pi_ager_names.mi_data_key) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + Mi_Timeout = 120 + mi_data = pi_ager_database.get_table_row('atc_data', 1) +# mi_data = pi_ager_database.get_table_value_from_field(pi_ager_names.atc_mi_thermometer_data_table, pi_ager_names.mi_data_key) if (mi_data != None): - splited_data = mi_data.split(' ') +# splited_data = mi_data.split(' ') try: - self.address = splited_data[1] - self.temperature = float(splited_data[2]) - self.humidity = float(splited_data[3]) - self.battery = float(splited_data[4]) - self.data_timestamp = int(splited_data[5]) # time in seconds when data was generated +# self.address = splited_data[1] +# self.temperature = float(splited_data[2]) +# self.humidity = float(splited_data[3]) +# self.battery = float(splited_data[4]) +# self.data_timestamp = int(splited_data[5]) # time in seconds when data was generated +# self.address = splited_data[1] + self.temperature = mi_data['temperature'] + self.humidity = mi_data['humidity'] + self.battery = mi_data['battvolt'] + self.data_timestamp = mi_data['last_change'] # time in seconds when data was generated current_time = int(time.time()) # current time in seconds if (current_time - self.data_timestamp) > Mi_Timeout: # when difference is greater than Mi_Timeout, then bluetooth connection may be broken if self.event_out_of_range == False: @@ -45,6 +51,13 @@ def get_current_data(self): cl_fact_logic_messenger().get_instance().handle_event('Mi_Sensor_failed') #if the second parameter is empty, the value is taken from the field envent_text in table config_messenger_event pi_ager_database.update_table_val(pi_ager_names.current_values_table, pi_ager_names.MiSensor_battery_key, None) return(None,None,None,None) + + hum_offset = self.get_humidity_offset() + self.humidity += hum_offset + if (self.humidity > 100.0): + self.humidity = 100.0 + if (self.humidity < 0.0): + self.humidity = 0.0 (self.dewpoint, self.absolute_humidity) = super().get_dewpoint(self.temperature, self.humidity) self.measured_data = (self.temperature, self.humidity, self.dewpoint, self.absolute_humidity) @@ -64,25 +77,6 @@ def get_current_data(self): cl_fact_logger.get_instance().debug('MiThermometerData : ' + 'Data error') pi_ager_database.update_table_val(pi_ager_names.current_values_table, pi_ager_names.MiSensor_battery_key, None) return(None,None,None,None) - - - def _write_to_db(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - def execute(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - def soft_reset(self): - """Performs Soft Reset on SHT chip""" - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - def set_heading_on(self): - """Switch the heading on the sensor on""" - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - def set_heading_off(self): - """Switch the heading on the sensor off""" - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) class cl_fact_sensor_MiThermometer: @@ -91,7 +85,7 @@ class cl_fact_sensor_MiThermometer: @classmethod def get_instance(self, i_sensor_type, i_active_sensor): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) if cl_fact_sensor_MiThermometer.__o_instance is not None: return(cl_fact_sensor_MiThermometer.__o_instance) cl_fact_sensor_MiThermometer.__o_instance = cl_sensor_MiThermometer(i_sensor_type, i_active_sensor) @@ -99,10 +93,10 @@ def get_instance(self, i_sensor_type, i_active_sensor): @classmethod def set_instance(self, i_instance): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_sensor_MiThermometer.__o_instance = i_instance def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) pass diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_aht.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_aht.py new file mode 100644 index 000000000..e2ae27d99 --- /dev/null +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_aht.py @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- + +"""This class is for handling the AHT sensors AHT10, AHT20, AHT21, AHT30 with i2c bus interface from ASAIR.""" +""" Default is setup fpr AHT2x and AHT30 """ + +import inspect +from main.pi_ager_cl_logger import cl_fact_logger +from smbus2 import i2c_msg +import time +from sensors.pi_ager_cl_i2c_bus import cl_fact_i2c_bus_logic +# from sensors.pi_ager_cl_i2c_sensor_aht import cl_fact_i2c_sensor_aht +from main.pi_ager_cx_exception import * +from sensors.pi_ager_cl_sensor import cl_sensor + +class cl_sensor_aht(cl_sensor): + AHTxx_I2CADDR = 0x38 + AHTxx_CMD_SOFTRESET = [0xBA] + AHT10_CMD_INITIALIZE = [0xE1, 0x08, 0x00] + AHT20_CMD_INITIALIZE = [0xBE, 0x08, 0x00] + AHTxx_CMD_MEASURE = [0xAC, 0x33, 0x00] + + # Initial value. Equal to bit negation the first data (status of AHT20) + CRC_INIT = 0xFF + # CRC polynomial G(x) = x8 + x5 + x4 + 1 + CRC_POLY = 0x31 + +#---------------------------------------------------------------------------------------------------------------------------------------------# + + def __init__(self, i_sensor_type, i_active_sensor, i_address): + # i_active_sensor : 'MAIN' or 'SECOND' + # i_sensor_type : class cl_main_sensor_type or cl_second_sensor_type + # i_address : i2c address + cl_fact_logger.get_instance().debug("i2c address is " + hex(i_address) + ". active sensor is : " + i_active_sensor + ". i_sensor_type is : " + i_sensor_type.get_sensor_type_ui()) + + self.o_address = i_address + self.o_sensor_type = i_sensor_type + self.o_active_sensor = i_active_sensor + + super().__init__(self.o_sensor_type) + + self._i2c_bus = cl_fact_i2c_bus_logic.get_instance().get_i2c_bus() + cl_fact_logger.get_instance().debug("i2c bus object is : " + str(self._i2c_bus)) + # self._i2c_sensor = cl_fact_i2c_sensor_aht.get_instance(self.o_active_sensor, self._i2c_bus, self.o_address) + + def check_init_status(self): + # check if sensor status after power on is ok, if not, raise exception + status = self.get_status() + if ((status & 0x18) != 0x18): + self.cmd_initialize() + status = self.get_status() + if ((status & 0x18) != 0x18): + raise cx_measurement_error (_('Error initializing AHTxx sensor!')) + + def cmd_soft_reset(self): + # Send the command to soft reset + write = i2c_msg.write(self.o_address, self.AHTxx_CMD_SOFTRESET) + self._i2c_bus.i2c_rdwr(write) + time.sleep(0.02) + + def cmd_initialize(self): + # Send the command to initialize (calibrate) + write = i2c_msg.write(self.o_address, self.AHT20_CMD_INITIALIZE) + self._i2c_bus.i2c_rdwr(write) + time.sleep(0.02) + + def get_status(self): + # Get the full status byte + read = i2c_msg.read(self.o_address, 1) + self._i2c_bus.i2c_rdwr(read) + buf = list(read) + time.sleep(0.01) + return buf[0] + + def cmd_measure(self): + # Send the command to measure + write = i2c_msg.write(self.o_address, self.AHTxx_CMD_MEASURE) + self._i2c_bus.i2c_rdwr(write) + time.sleep(0.08) # Wait 80 ms after measure + + def get_measure(self): + # Get the full measure + self.cmd_measure() + read = i2c_msg.read(self.o_address, 7) + self._i2c_bus.i2c_rdwr(read) + buf = list(read) + return buf + + def a_aht_calc_crc(self, data, len): + crc = self.CRC_INIT + + for byte in range(len): # len times + crc ^= data[byte] # xor byte + for i in range(8): # one byte + if ((crc & 0x80) != 0): # if high + crc = (crc << 1) ^ self.CRC_POLY # xor 0x31 + else: + crc = crc << 1 # skip + + return crc & 0xff + + def get_current_data(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + + repeat_count = 0 + repeat_count_max = 2 + while repeat_count < repeat_count_max: + try: + buf = self.get_measure() + if ((buf[0] & 0x80) != 0): # check busy + repeat_count += 1 + continue + + if (self.a_aht_calc_crc(buf, 6) != buf[6]): + repeat_count += 1 + continue + + hum_offset = self.get_humidity_offset() + humidity_raw = ((buf[1]) << 16) | ((buf[2]) << 8) | buf[3] # set the humidity + humidity_raw = (humidity_raw) >> 4 # right shift 4 + humidity_s = (humidity_raw / 1048576.0 * 100.0) # convert the humidity + humidity_s += hum_offset + if (humidity_s > 100.0): + humidity_s = 100.0 + if (humidity_s < 0.0): + humidity_s = 0.0 + + temperature_raw = ((buf[3]) << 16) | ((buf[4]) << 8) | buf[5] # set the temperature + temperature_raw = temperature_raw & 0xFFFFF # cut the temperature part + temperature_s = temperature_raw / 1048576.0 * 200.0 - 50.0 + + cl_fact_logger.get_instance().debug(f"AHT2x/30 temperature : {temperature_s:.2f}") + cl_fact_logger.get_instance().debug(f"AHT2x/30 humidity : {humidity_s:.1f}") + dewpoint = super().get_dewpoint(temperature_s, humidity_s) + (temperature_dewpoint, humidity_absolute) = dewpoint + + self.measured_data = (temperature_s, humidity_s, temperature_dewpoint, humidity_absolute) + return(self.measured_data) + + except Exception as cx_error: + repeat_count += 1 + if (repeat_count == 1): + cl_fact_logger.get_instance().exception(cx_error) + else: + cl_fact_logger.get_instance().error(f"Retry getting measurement from I2C device AHT2x/3x. Current retry count : {repeat_count}, max retry count : {repeat_count_max}") + + raise cx_measurement_error (_('Too many measurement errors occurred!')) diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_aht1x.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_aht1x.py new file mode 100644 index 000000000..8448dbeb5 --- /dev/null +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_aht1x.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- + +"""This class is for handling the AHT1x sensor """ + +import inspect +from main.pi_ager_cl_logger import cl_fact_logger +from smbus2 import i2c_msg +import time + +from abc import ABC, abstractmethod +from main.pi_ager_cx_exception import * +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +from sensors.pi_ager_cl_sensor_aht import cl_sensor_aht + +class cl_sensor_aht1x(cl_sensor_aht): + # i_active_sensor : 'MAIN' or 'SECOND' + # i_sensor_type : class cl_main_sensor_type or cl_second_sensor_type + # i_address : i2c address + def __init__(self, i_sensor_type, i_active_sensor, i_address): + # cl_fact_logger.get_instance().debug("i2c address is : " + hex(i_address) + ". active sensor is : " + i_active_sensor + ". i_sensor_type is : " + i_sensor_type.get_sensor_type_ui()) + cl_fact_logger.get_instance().debug("i2c address is : " + (str(i_address) if i_address == None else hex(i_address)) + ". active sensor is : " + str(i_active_sensor) + ". i_sensor_type is : " + i_sensor_type.get_sensor_type_ui()) + self.o_sensor_type = i_sensor_type + self.o_address = i_address + + super().__init__(self.o_sensor_type, i_active_sensor, self.o_address) + self.check_init_status() + + def check_init_status(self): + # check if sensor status after power on is ok, if not, raise exception + status = self.get_status() + if ((status & 0x08) != 0x08): + self.cmd_initialize() + status = self.get_status() + if ((status & 0x08) != 0x08): + raise cx_measurement_error (_('Error initializing AHTxx sensor!')) + + def cmd_initialize(self): + # Send the command to initialize (calibrate) + write = i2c_msg.write(self.o_address, self.AHT10_CMD_INITIALIZE) + self._i2c_bus.i2c_rdwr(write) + time.sleep(0.02) + + def get_measure(self): + # Get the full measure + self.cmd_measure() + read = i2c_msg.read(self.o_address, 6) + self._i2c_bus.i2c_rdwr(read) + buf = list(read) + return buf + + def get_current_data(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + + repeat_count = 0 + repeat_count_max = 2 + while repeat_count < repeat_count_max: + try: + buf = self.get_measure() + if ((buf[0] & 0x80) != 0): # check busy + repeat_count += 1 + continue + + hum_offset = self.get_humidity_offset() + humidity_raw = ((buf[1]) << 16) | ((buf[2]) << 8) | buf[3] # set the humidity + humidity_raw = (humidity_raw) >> 4 # right shift 4 + humidity_s = (humidity_raw / 1048576.0 * 100.0) # convert the humidity + humidity_s += hum_offset # add offset + if (humidity_s > 100.0): + humidity_s = 100.0 + if (humidity_s < 0.0): + humidity_s = 0.0 + + temperature_raw = ((buf[3]) << 16) | ((buf[4]) << 8) | buf[5] # set the temperature + temperature_raw = temperature_raw & 0xFFFFF # cut the temperature part + temperature_s = temperature_raw / 1048576.0 * 200.0 - 50.0 + + cl_fact_logger.get_instance().debug(f"AHT1x temperature : {temperature_s:.2f}") + cl_fact_logger.get_instance().debug(f"AHT1x humidity : {humidity_s:.1f}") + dewpoint = super().get_dewpoint(temperature_s, humidity_s) + (temperature_dewpoint, humidity_absolute) = dewpoint + + self.measured_data = (temperature_s, humidity_s, temperature_dewpoint, humidity_absolute) + return(self.measured_data) + + except Exception as cx_error: + repeat_count += 1 + if (repeat_count == 1): + cl_fact_logger.get_instance().exception(cx_error) + else: + cl_fact_logger.get_instance().error(f"Retry getting measurement from I2C device AHT1x. Current retry count : {repeat_count}, max retry count : {repeat_count_max}") + + raise cx_measurement_error (_('Too many measurement errors occurred!')) + + +class cl_fact_sensor_aht1x(ABC): + __o_instance = None + __ot_instances = {} + + @classmethod + def get_instance(self, i_sensor_type, i_active_sensor, i_address): + cl_fact_logger.get_instance().debug("cl_fact_sensor_aht1x.get_instance") + cl_fact_logger.get_instance().debug("Old aht1x __ot_instances = " + str(cl_fact_sensor_aht1x.__ot_instances)) + + cl_fact_sensor_aht1x.__o_instance = cl_fact_sensor_aht1x.__ot_instances.get(i_active_sensor) + if cl_fact_sensor_aht1x.__o_instance is not None : + cl_fact_logger.get_instance().debug("aht1x __ot_instance = " + str(cl_fact_sensor_aht1x.__o_instance)+ " Returning") + return(cl_fact_sensor_aht1x.__o_instance) + + cl_fact_sensor_aht1x.__o_instance = cl_sensor_aht1x(i_sensor_type, i_active_sensor, i_address) + cl_fact_logger.get_instance().debug("aht1x __ot_instance " + i_active_sensor + str(cl_fact_sensor_aht1x.__o_instance) + " created for " ) + line = {i_active_sensor:cl_fact_sensor_aht1x.__o_instance} + cl_fact_sensor_aht1x.__ot_instances.update(line) + cl_fact_logger.get_instance().debug("New aht1x __ot_instances = " + str(cl_fact_sensor_aht1x.__ot_instances)) + return(cl_fact_sensor_aht1x.__o_instance) + + @classmethod + def set_instance(self, i_active_sensor, i_instance): + cl_fact_sensor_aht1x.__o_instance = i_instance + + def __init__(self): + pass + diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_aht2x.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_aht2x.py new file mode 100644 index 000000000..3b3ca5ba5 --- /dev/null +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_aht2x.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +"""This class is for handling the AHT2x sensor """ + +import inspect +from main.pi_ager_cl_logger import cl_fact_logger +import time + +from abc import ABC, abstractmethod +from main.pi_ager_cx_exception import * +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +from sensors.pi_ager_cl_sensor_aht import cl_sensor_aht + +class cl_sensor_aht2x(cl_sensor_aht): + # i_active_sensor : 'MAIN' or 'SECOND' + # i_sensor_type : class cl_main_sensor_type or cl_second_sensor_type + # i_address : i2c address + def __init__(self, i_sensor_type, i_active_sensor, i_address): + # cl_fact_logger.get_instance().debug("i2c address is : " + hex(i_address) + ". active sensor is : " + i_active_sensor + ". i_sensor_type is : " + i_sensor_type.get_sensor_type_ui()) + cl_fact_logger.get_instance().debug("i2c address is : " + (str(i_address) if i_address == None else hex(i_address)) + ". active sensor is : " + str(i_active_sensor) + ". i_sensor_type is : " + i_sensor_type.get_sensor_type_ui()) + self.o_sensor_type = i_sensor_type + self.o_address = i_address + + super().__init__(self.o_sensor_type, i_active_sensor, self.o_address) + self.check_init_status() + + def get_current_data(self): + self.measured_data = super().get_current_data() + return(self.measured_data) + + +class cl_fact_sensor_aht2x(ABC): + __o_instance = None + __ot_instances = {} + @classmethod + def get_instance(self, i_sensor_type, i_active_sensor, i_address): + cl_fact_logger.get_instance().debug("cl_fact_sensor_aht2x.get_instance") + cl_fact_logger.get_instance().debug("Old aht2x __ot_instances = " + str(cl_fact_sensor_aht2x.__ot_instances)) + + cl_fact_sensor_aht2x.__o_instance = cl_fact_sensor_aht2x.__ot_instances.get(i_active_sensor) + if cl_fact_sensor_aht2x.__o_instance is not None : + cl_fact_logger.get_instance().debug("aht2x __ot_instance = " + str(cl_fact_sensor_aht2x.__o_instance)+ " Returning") + return(cl_fact_sensor_aht2x.__o_instance) + +# try: +# cl_fact_sensor_aht2x.__o_instance = cl_fact_sensor_aht2x.__ot_instances.pop(i_active_sensor) +# cl_fact_logger.get_instance().debug("aht2x __ot_instance for " + i_active_sensor + " = " + str(cl_fact_sensor_aht2x.__o_instance)) +# except KeyError: +# cl_fact_logger.get_instance().debug("aht2x __ot_instance not found for " + i_active_sensor) +# cl_fact_sensor_aht2x.__o_instance = None +# if cl_fact_sensor_aht2x.__o_instance is not None : +# cl_fact_logger.get_instance().debug("aht2x __ot_instance = " + str(cl_fact_sensor_aht2x.__o_instance)+ " Returning") +# return(cl_fact_sensor_aht3x.__o_instance) + + cl_fact_sensor_aht2x.__o_instance = cl_sensor_aht2x(i_sensor_type, i_active_sensor, i_address) + cl_fact_logger.get_instance().debug("aht2x __ot_instance " + i_active_sensor + str(cl_fact_sensor_aht2x.__o_instance) + " created for " ) + line = {i_active_sensor:cl_fact_sensor_aht2x.__o_instance} + cl_fact_sensor_aht2x.__ot_instances.update(line) + cl_fact_logger.get_instance().debug("New aht2x __ot_instances = " + str(cl_fact_sensor_aht2x.__ot_instances)) + return(cl_fact_sensor_aht2x.__o_instance) + + @classmethod + def set_instance(self, i_active_sensor, i_instance): + cl_fact_sensor_aht2x.__o_instance = i_instance + + def __init__(self): + pass + diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_aht30.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_aht30.py new file mode 100644 index 000000000..16ce94866 --- /dev/null +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_aht30.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +"""This class is for handling the AHT30 sensor """ + +import inspect +# import pi_ager_names +# from pi_ager_database import get_table_row +from main.pi_ager_cl_logger import cl_fact_logger +import time + +from abc import ABC, abstractmethod +from main.pi_ager_cx_exception import * +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +from sensors.pi_ager_cl_sensor_aht import cl_sensor_aht + +class cl_sensor_aht30(cl_sensor_aht): + # i_active_sensor : 'MAIN' or 'SECOND' + # i_sensor_type : class cl_main_sensor_type or cl_second_sensor_type + # i_address : i2c address + def __init__(self, i_sensor_type, i_active_sensor, i_address): + # cl_fact_logger.get_instance().debug("i2c address is : " + hex(i_address) + ". active sensor is : " + i_active_sensor + ". i_sensor_type is : " + i_sensor_type.get_sensor_type_ui()) + cl_fact_logger.get_instance().debug("i2c address is : " + str(i_address) + ". active sensor is : " + str(i_active_sensor) + ". i_sensor_type is : " + str(i_sensor_type)) + self.o_sensor_type = i_sensor_type + self.o_address = i_address + + super().__init__(self.o_sensor_type, i_active_sensor, self.o_address) + # humidity_offsets = get_table_row(pi_ager_names.humidity_offset_table, 1) + # self.humidity_offset = humidity_offsets['AHT30'] + + self.check_init_status() + + def get_current_data(self): + return super().get_current_data() + +class cl_fact_sensor_aht30(ABC): + __o_instance = None + __ot_instances = {} + @classmethod + def get_instance(self, i_sensor_type, i_active_sensor, i_address): + cl_fact_logger.get_instance().debug("cl_fact_sensor_aht30.get_instance") + cl_fact_logger.get_instance().debug("Old aht30 __ot_instances = " + str(cl_fact_sensor_aht30.__ot_instances)) + + cl_fact_sensor_aht30.__o_instance = cl_fact_sensor_aht30.__ot_instances.get(i_active_sensor) + if cl_fact_sensor_aht30.__o_instance is not None : + cl_fact_logger.get_instance().debug("aht30 __ot_instance = " + str(cl_fact_sensor_aht30.__o_instance)+ " Returning") + return(cl_fact_sensor_aht30.__o_instance) + + cl_fact_sensor_aht30.__o_instance = cl_sensor_aht30(i_sensor_type, i_active_sensor, i_address) + cl_fact_logger.get_instance().debug("aht30 __ot_instance " + i_active_sensor + str(cl_fact_sensor_aht30.__o_instance) + " created for " ) + line = {i_active_sensor:cl_fact_sensor_aht30.__o_instance} + cl_fact_sensor_aht30.__ot_instances.update(line) + cl_fact_logger.get_instance().debug("New aht30 __ot_instances = " + str(cl_fact_sensor_aht30.__ot_instances)) + return(cl_fact_sensor_aht30.__o_instance) + + @classmethod + def set_instance(self, i_active_sensor, i_instance): + cl_fact_sensor_aht30.__o_instance = i_instance + + def __init__(self): + pass + diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_dht11.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_dht11.py index c704488ff..881e8f0ca 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_sensor_dht11.py +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_dht11.py @@ -11,18 +11,18 @@ __email__ = "DerBurgermeister@pi-ager.org" __status__ = "Production" -#from abc import ABC, abstractmethod -import inspect +from abc import ABC, abstractmethod +# import inspect from main.pi_ager_cl_logger import cl_fact_logger -import time +# import time import pi_ager_gpio_config -from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type +# from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type from main.pi_ager_cx_exception import * -from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger -from sensors.pi_ager_cl_sensor import cl_sensor# -from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +# from sensors.pi_ager_cl_sensor import cl_sensor +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor from sensors.pi_ager_cl_sensor_dht_adafruit import cl_sensor_dht_adafruit import Adafruit_DHT @@ -30,66 +30,27 @@ class cl_sensor_dht11(cl_sensor_dht_adafruit): def __init__(self, i_sensor_type, i_active_sensor): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if "get_instance" not in inspect.stack()[1][3]: - raise cx_direct_call(self,"Please use factory class" ) - self.o_sensor_type = i__sensor_type + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # if "get_instance" not in inspect.stack()[1][3]: + # raise cx_direct_call(self,"Please use factory class" ) + # self.o_sensor_type = i__sensor_type self._sensor_dht = Adafruit_DHT.DHT11 - #self.o_sensor_type = cl_fact_main_sensor_type.get_instance() - super().__init__(self.o_sensor_type) - - - self._max_errors = 3 - self._old_temperature = 0 - self._current_temperature = 0 - self._temperature_dewpoint = 0 - self._humidity_absolute = 0 - self._old_humidity = 0 - self._current_humidity = 0 - - + # super().__init__(self.o_sensor_type) + super().__init__() def get_current_data(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self.measured_data = super().get_current_data() return(self.measured_data) - - def _write_to_db(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - super()._write_to_db() - pass - - def execute(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - #self.get_current_data() - self._write_to_db() - -class th_sensor_dht11(cl_sensor_dht11): - - NAME = 'Sensor DHT11' - - - def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self.get_type_raise = False - self._type = "DHT11" - - def get_type(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if self.get_type_raise == True: - raise cx_Sensor_not_defined(self._type_ui) - return(self._type) -class cl_fact_sensor_dht11: - fact_main_sensor_type = cl_fact_main_sensor_type() -# Only a singleton instance for main_sensor - #__o_sensor_type = fact_main_sensor_type.get_instance() +class cl_fact_sensor_dht11(ABC): + # fact_main_sensor_type = cl_fact_main_sensor_type() __o_instance = None @classmethod def get_instance(self, i_sensor_type, i_active_sensor): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) if cl_fact_sensor_dht11.__o_instance is not None: return(cl_fact_sensor_dht11.__o_instance) cl_fact_sensor_dht11.__o_instance = cl_sensor_dht11(i_sensor_type, i_active_sensor) @@ -97,11 +58,10 @@ def get_instance(self, i_sensor_type, i_active_sensor): @classmethod def set_instance(self, i_instance): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_sensor_dht11.__o_instance = i_instance - def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) pass diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_dht22.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_dht22.py index 6629a2d09..3c758797d 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_sensor_dht22.py +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_dht22.py @@ -11,18 +11,18 @@ __email__ = "DerBurgermeister@pi-ager.org" __status__ = "Production" -#from abc import ABC, abstractmethod -import inspect +from abc import ABC, abstractmethod +# import inspect from main.pi_ager_cl_logger import cl_fact_logger -import time +# import time -import pi_ager_gpio_config +# import pi_ager_gpio_config -from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type +# from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type from main.pi_ager_cx_exception import * -from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger -from sensors.pi_ager_cl_sensor import cl_sensor# -from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +# from sensors.pi_ager_cl_sensor import cl_sensor +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor from sensors.pi_ager_cl_sensor_dht_adafruit import cl_sensor_dht_adafruit import Adafruit_DHT @@ -30,66 +30,27 @@ class cl_sensor_dht22(cl_sensor_dht_adafruit): def __init__(self, i_sensor_type, i_active_sensor): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if "get_instance" not in inspect.stack()[1][3]: - raise cx_direct_call(self,"Please use factory class" ) - self.o_sensor_type = i_sensor_type + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # if "get_instance" not in inspect.stack()[1][3]: + # raise cx_direct_call(self,"Please use factory class" ) + # self.o_sensor_type = i_sensor_type self._sensor_dht = Adafruit_DHT.DHT22 - #self.o_sensor_type = cl_fact_main_sensor_type.get_instance() - super().__init__(self.o_sensor_type) - - - self._max_errors = 3 - self._old_temperature = 0 - self._current_temperature = 0 - self._temperature_dewpoint = 0 - self._humidity_absolute = 0 - self._old_humidity = 0 - self._current_humidity = 0 - - + # super().__init__(self.o_sensor_type) + super().__init__() def get_current_data(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self.measured_data = super().get_current_data() return(self.measured_data) - - def _write_to_db(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - super()._write_to_db() - pass - - def execute(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - #self.get_current_data() - self._write_to_db() - -class th_sensor_dht22(cl_sensor_dht22): - - NAME = 'Sensor SHT22' - - - def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self.get_type_raise = False - self._type = "DHT22" - - def get_type(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if self.get_type_raise == True: - raise cx_Sensor_not_defined(self._type_ui) - return(self._type) -class cl_fact_sensor_dht22: - fact_main_sensor_type = cl_fact_main_sensor_type() -# Only a singleton instance for main_sensor - #__o_sensor_type = fact_main_sensor_type.get_instance() +class cl_fact_sensor_dht22(ABC): + # fact_main_sensor_type = cl_fact_main_sensor_type() __o_instance = None @classmethod def get_instance(self, i_sensor_type, i_active_sensor): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) if cl_fact_sensor_dht22.__o_instance is not None: return(cl_fact_sensor_dht22.__o_instance) cl_fact_sensor_dht22.__o_instance = cl_sensor_dht22(i_sensor_type, i_active_sensor) @@ -97,11 +58,11 @@ def get_instance(self, i_sensor_type, i_active_sensor): @classmethod def set_instance(self, i_instance): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_sensor_dht22.__o_instance = i_instance def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) pass diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_dht_adafruit.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_dht_adafruit.py index 535fdef07..c40c8fc0c 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_sensor_dht_adafruit.py +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_dht_adafruit.py @@ -19,30 +19,26 @@ from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type from main.pi_ager_cx_exception import * -from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger -from sensors.pi_ager_cl_sensor import cl_sensor # -from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +from sensors.pi_ager_cl_sensor import cl_sensor +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor import Adafruit_DHT class cl_sensor_dht_adafruit(cl_sensor): - def __init__(self, i_sensor_dht): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + def __init__(self): +# cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) super().__init__(cl_fact_main_sensor_type.get_instance()) self._pin = pi_ager_gpio_config.gpio_sensor_data self._max_errors = 3 - self._old_temperature = 0 self._current_temperature = 0 - self._temperature_dewpoint = 0 - self._humidity_absolute = 0 - self._old_humidity = 0 self._current_humidity = 0 def get_current_data(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) +# cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self._error_counter = 0 while self._error_counter < self._max_errors: @@ -58,6 +54,13 @@ def get_current_data(self): if ( self._current_temperature == None or self._current_humidity == None ): raise ValueError + hum_offset = self.get_humidity_offset() + self._current_humidity += hum_offset + if (self._current_humidity > 100.0): + self._current_humidity = 100.0 + if (self._current_humidity < 0.0): + self._current_humidity = 0.0 + cl_fact_logger.get_instance().debug("Temperature in Celsius is : %.2f °C" %self._current_temperature) cl_fact_logger.get_instance().debug("Relative Humidity is : %.2f %%RH" %self._current_humidity) self._dewpoint = super().get_dewpoint(self._current_temperature, self._current_humidity) @@ -74,46 +77,7 @@ def get_current_data(self): cl_fact_logger.get_instance().error(f"Retry getting measurement from DHT device. Current retry count : {self._error_counter}, max retry count : {self._max_errors}") time.sleep(1) -# self.delete_error_counter() - cl_fact_logger.get_instance().debug('Too many measurement errors occurred!') + cl_fact_logger.get_instance().debug(_('Too many measurement errors occurred!')) raise cx_measurement_error (_('Too many measurement errors occurred!')) - - def _write_to_db(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - super()._write_to_db() - pass - def execute(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - #self.get_current_data() - self._write_to_db() - - def set_heading_on(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug('Not avaiable for this sensor type') - - def set_heading_off(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug('Not avaiable for this sensor type') - - def soft_reset(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug('Not avaiable for this sensor type') - -class th_sensor_dht_adafruit(cl_sensor_dht_adafruit): -# SUPPORTED_MAIN_SENSOR_TYPES = ["dht_adafruit", "dht_adafruit", "DHT22"] - NAME = 'Main_sensor' - - - def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self.get_type_raise = False - self._type = "dht_adafruit" - - def get_type(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if self.get_type_raise == True: - raise cx_Sensor_not_defined(self._type_ui) - return(self._type) - diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_fact.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_fact.py index 05601e4ad..a602506a1 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_sensor_fact.py +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_fact.py @@ -11,7 +11,7 @@ __status__ = "Production" from abc import ABC, abstractmethod -import inspect +# import inspect from main.pi_ager_cl_logger import cl_fact_logger from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type, cl_fact_second_sensor_type from main.pi_ager_cx_exception import * @@ -20,9 +20,13 @@ from sensors.pi_ager_cl_sensor_sht85 import cl_fact_sensor_sht85 from sensors.pi_ager_cl_sensor_dht11 import cl_fact_sensor_dht11 from sensors.pi_ager_cl_sensor_dht22 import cl_fact_sensor_dht22 +from sensors.pi_ager_cl_sensor_aht1x import cl_fact_sensor_aht1x +from sensors.pi_ager_cl_sensor_aht2x import cl_fact_sensor_aht2x +from sensors.pi_ager_cl_sensor_aht30 import cl_fact_sensor_aht30 +from sensors.pi_ager_cl_sensor_sht4x import cl_fact_sensor_sht4x from sensors.pi_ager_cl_sensor_MiThermometer import cl_fact_sensor_MiThermometer -class cl_fact_sensor: +class cl_fact_sensor(ABC): # Only a singleton instance for main_sensor __o_sensor_type = None __o_instance = None @@ -30,54 +34,59 @@ class cl_fact_sensor: @classmethod def get_instance(self, i_active_sensor, i_address=None): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_logger.get_instance().debug("Old i2c__ot_instances = " + str(cl_fact_sensor.__ot_instances)) if i_active_sensor == "MAIN": - cl_fact_sensor.__o_sensor_type = cl_fact_main_sensor_type().get_instance() + cl_fact_sensor.__o_sensor_type = cl_fact_main_sensor_type().get_instance() elif i_active_sensor == "SECOND": cl_fact_sensor.__o_sensor_type = cl_fact_second_sensor_type().get_instance() l_sensor_type = cl_fact_sensor.__o_sensor_type - cl_fact_logger.get_instance().debug("Active Sensor = " + i_active_sensor + " with type " + l_sensor_type.get_sensor_type_ui() + " and address " + str(i_address)) - try: - cl_fact_sensor.__o_instance = cl_fact_sensor.__ot_instances.pop(i_active_sensor) - cl_fact_logger.get_instance().debug("__ot_instance for " + i_active_sensor + " = " + str(cl_fact_sensor.__ot_instances)) - except KeyError: - cl_fact_sensor.__o_instance = None - - if cl_fact_sensor.__o_instance is not None : + if i_address is not None: + cl_fact_logger.get_instance().debug("Active Sensor = " + i_active_sensor + " with type " + l_sensor_type.get_sensor_type_ui() + " and address " + hex(i_address)) + else: + cl_fact_logger.get_instance().debug("Active Sensor = " + i_active_sensor + " with type " + l_sensor_type.get_sensor_type_ui()) + + cl_fact_sensor.__o_instance = cl_fact_sensor.__ot_instances.get(i_active_sensor) + if cl_fact_sensor.__o_instance is not None : cl_fact_logger.get_instance().debug("Returning __ot_instance = " + str(cl_fact_sensor.__o_instance)) return(cl_fact_sensor.__o_instance) -# try: - if cl_fact_sensor.__o_sensor_type._get_type_ui( ) == 'SHT75': + + sensor_name = cl_fact_sensor.__o_sensor_type._get_type_ui() + + if sensor_name == 'SHT75': cl_fact_sensor.__o_instance = cl_fact_sensor_sht75.get_instance(l_sensor_type, i_active_sensor) - elif cl_fact_sensor.__o_sensor_type._get_type_ui( ) == 'SHT3x': + elif sensor_name == 'SHT3x' or sensor_name == 'SHT3x-mod': cl_fact_sensor.__o_instance = cl_fact_sensor_sht3x.get_instance(l_sensor_type, i_active_sensor, i_address) - elif cl_fact_sensor.__o_sensor_type._get_type_ui( ) == 'SHT85': + elif sensor_name == 'SHT85': cl_fact_sensor.__o_instance = cl_fact_sensor_sht85.get_instance(l_sensor_type, i_active_sensor, i_address) - elif cl_fact_sensor.__o_sensor_type._get_type_ui( ) == 'DHT22': + elif sensor_name == 'DHT22': cl_fact_sensor.__o_instance = cl_fact_sensor_dht22.get_instance(l_sensor_type, i_active_sensor) - elif cl_fact_sensor.__o_sensor_type._get_type_ui( ) == 'DHT11': + elif sensor_name == 'DHT11': cl_fact_sensor.__o_instance = cl_fact_sensor_dht11.get_instance(l_sensor_type, i_active_sensor) - elif cl_fact_sensor.__o_sensor_type._get_type_ui( ) == 'MiThermometer': + elif sensor_name == 'MiThermometer': cl_fact_sensor.__o_instance = cl_fact_sensor_MiThermometer.get_instance(l_sensor_type, i_active_sensor) + elif sensor_name == 'AHT2x': + cl_fact_sensor.__o_instance = cl_fact_sensor_aht2x.get_instance(l_sensor_type, i_active_sensor, i_address) + elif sensor_name == 'AHT30': + cl_fact_sensor.__o_instance = cl_fact_sensor_aht30.get_instance(l_sensor_type, i_active_sensor, i_address) + elif sensor_name == 'SHT4x-A' or sensor_name == 'SHT4X-B' or sensor_name == 'SHT4x-C': + cl_fact_sensor.__o_instance = cl_fact_sensor_sht4x.get_instance(l_sensor_type, i_active_sensor, i_address) + elif sensor_name == 'AHT1x' or sensor_name == 'AHT1x-mod': + cl_fact_sensor.__o_instance = cl_fact_sensor_aht1x.get_instance(l_sensor_type, i_active_sensor, i_address) cl_fact_logger.get_instance().debug("__ot_instance for " + i_active_sensor + " = " + str(cl_fact_sensor.__o_instance) + " created" ) - cl_fact_logger.get_instance().debug("__ot_instances = " + str(cl_fact_sensor.__ot_instances)) line = {i_active_sensor:cl_fact_sensor.__o_instance} cl_fact_sensor.__ot_instances.update(line) - cl_fact_logger.get_instance().debug("__ot_instances = " + str(cl_fact_sensor.__ot_instances)) -# except Exception as original_error: -# raise original_error + return(cl_fact_sensor.__o_instance) @classmethod def set_instance(self, i_instance): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_sensor.__o_instance = i_instance def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) pass diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_sht.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht.py index 79de2df72..413d39fe4 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_sensor_sht.py +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht.py @@ -15,269 +15,151 @@ import inspect # import pi_ager_logging from main.pi_ager_cl_logger import cl_fact_logger +from smbus2 import i2c_msg import time -from abc import ABC, abstractmethod -from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type +# from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type from sensors.pi_ager_cl_i2c_bus import cl_fact_i2c_bus_logic -from sensors.pi_ager_cl_i2c_sensor_sht import cl_fact_i2c_sensor_sht +# from sensors.pi_ager_cl_i2c_sensor_sht import cl_fact_i2c_sensor_sht from main.pi_ager_cx_exception import * -from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger -from sensors.pi_ager_cl_sensor import cl_sensor# -from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +from sensors.pi_ager_cl_sensor import cl_sensor +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor -class cl_sensor_sht(cl_sensor, ABC): - - _RESET = 0x30A2 - _HEATER_ON = 0x306D - _HEATER_OFF = 0x3066 - _STATUS = 0xF32D - _TRIGGER = 0x2C06 - _STATUS_BITS_MASK = 0xFFFC +class cl_sensor_sht(cl_sensor): + SHT_CMD_SOFTRESET = [0x30, 0xa2] + SHT_CMD_MEASURE = [0x2c, 0x06] + SHT_CMD_STATUS = [0xf3, 0x2d] + + # Initial value. Equal to bit negation the first data (status of AHT20) + CRC_INIT = 0xFF + # CRC polynomial G(x) = x8 + x5 + x4 + 1 + CRC_POLY = 0x31 - def __init__(self, i_active_sensor, i_sensor_type, i_address): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug("i2c address is" + str(i_address)) + # i_active_sensor : 'MAIN' or 'SECOND' + # i_sensor_type : class cl_main_sensor_type or cl_second_sensor_type + # i_address : i2c address + def __init__(self, i_sensor_type, i_active_sensor, i_address): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + if i_address is not None: + cl_fact_logger.get_instance().debug("i2c address is " + hex(i_address)) - self._max_errors = 1 - self._old_temperature = 0 - self._current_temperature = 0 - self._temperature_dewpoint = 0 - self._humidity_absolute = 0 - self._old_humidity = 0 - self._current_humidity = 0 + self.repeat_count_max = 3 self.o_address = i_address - - - self._alert_pending = False - self._heater_status = False - self._humidity_tracking_alert = False - self._temperature_tracking_alert = False - self._system_reset_detected = False - self._command_status_successfully = False - - self.o_sensor_type = i_sensor_type - super().__init__(self.o_sensor_type) self.o_active_sensor= i_active_sensor - self._i2c_bus = cl_fact_i2c_bus_logic.get_instance().get_i2c_bus() - cl_fact_logger.get_instance().debug(self._i2c_bus) - self._i2c_sensor = cl_fact_i2c_sensor_sht.get_instance(self.o_active_sensor, self._i2c_bus, self.o_address) - - - - def _send_i2c_start_command(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - msb_data = 0x24 - lsb_data = 0x00 - - #Write the sensor data - self._i2c_bus.write_byte_data(self._i2c_sensor.get_address(), msb_data, lsb_data) - - time.sleep(0.01) #This is so the sensor has time to perform the measurement and write its registers before you read it - - msb_data = 0x21 - lsb_data = 0x30 - #Write the sensor data - self._i2c_bus.write_byte_data(self._i2c_sensor.get_address(), msb_data, lsb_data) - - time.sleep(0.01) #This is so the sensor has time to perform the measurement and write its registers before you read it - - - def _read_data(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - self._send_i2c_start_command() - self.data0 = self._i2c_bus.read_i2c_block_data(self._i2c_sensor.get_address(), 0x00, 8) + super().__init__(self.o_sensor_type) - self.t_val = (self.data0[0]<<8) + self.data0[1] #convert the data - self.h_val = (self.data0[3] <<8) + self.data0[4] # Convert the data - - "CRC Values" - t_crc_calc = self._i2c_sensor.calculate_checksum(self.t_val) - h_crc_calc = self._i2c_sensor.calculate_checksum(self.h_val) - - t_crc = self.data0[2] - h_crc = self.data0[5] + self._i2c_bus = cl_fact_i2c_bus_logic.get_instance().get_i2c_bus() + status = self.read_status_register() + if ((status & 0x0003) != 0x0): + self.soft_reset() + status = self.read_status_register() + if ((status & 0x0003) != 0x0): + raise cx_measurement_error (_('Error initializing SHT sensor!')) - localtime = time.asctime( time.localtime(time.time()) ) - if hex(t_crc_calc) != hex(t_crc): - cl_fact_logger.get_instance().debug("Local current time :", localtime) - cl_fact_logger.get_instance().debug("Temperature CRC calc is : %x " %t_crc_calc) - cl_fact_logger.get_instance().debug("Temperature CRC real is : %x " %t_crc) - cl_fact_logger.get_instance().error("CRC Error") - if (self._system_reset_detected == True): - cl_fact_main_sensor().set_instance(None) - else: - self.soft_reset() - self.clear_status_register() +# cl_fact_logger.get_instance().debug(self._i2c_bus) +# self._i2c_sensor = cl_fact_i2c_sensor_sht.get_instance(self.o_active_sensor, self._i2c_bus, self.o_address) - raise cx_i2c_sht_temperature_crc_error - - if hex(h_crc_calc) != hex(h_crc): - cl_fact_logger.get_instance().debug("Local current time :", localtime) - cl_fact_logger.get_instance().debug("Humidity CRC calc is : %x " %h_crc_calc) - cl_fact_logger.get_instance().debug("Humidity CRC real is : %x " %h_crc) - cl_fact_logger.get_instance().error("CRC Error") - if (self._system_reset_detected == True): - cl_fact_main_sensor().set_instance(None) - else: - self.soft_reset() - self.clear_status_register() - - raise cx_i2c_sht_humidity_crc_error + + def sht_calc_crc(self, data, len): + crc = self.CRC_INIT + + for byte in range(len): # len times + crc ^= data[byte] # xor byte + for i in range(8): # one byte + if ((crc & 0x80) != 0): # if high + crc = (crc << 1) ^ self.CRC_POLY # xor 0x31 + else: + crc = crc << 1 # skip - - - def clear_status_register(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - msb_data = 0x30 - lsb_data = 0x41 + return crc & 0xff - #Write the sensor data - self._i2c_bus.write_byte_data(self._i2c_sensor.get_address(), msb_data, lsb_data) + def cmd_measure(self): + # Send the command to measure + write = i2c_msg.write(self.o_address, self.SHT_CMD_MEASURE) + self._i2c_bus.i2c_rdwr(write) + time.sleep(0.02) #This is so the sensor has time to perform the measurement and write its registers before you read it + + def get_measure(self): + # Get the full measure + self.cmd_measure() + read = i2c_msg.read(self.o_address, 6) + self._i2c_bus.i2c_rdwr(read) + buf = list(read) + return buf - time.sleep(0.01) #This is so the sensor has ime to perform the measurement and write its registers before you read it - self.read_status_register() - def read_status_register(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - msb_data = 0xF3 - lsb_data = 0x2D - - #Write the sensor data - self._i2c_bus.write_byte_data(self._i2c_sensor.get_address(), msb_data, lsb_data) - - time.sleep(0.01) #This is so the sensor has tme to preform the mesurement and write its registers before you read it - - self.data0 = self._i2c_bus.read_i2c_block_data(self._i2c_sensor.get_address(), 0x00, 16) - - self.status_register = (self.data0[0]<<8) + self.data0[1] - cl_fact_logger.get_instance().debug("Status register is : %x " %self.status_register) - - if self.is_set(self.status_register, 15): self._alert_pending = True - else: self._alert_pending = False - if self.is_set(self.status_register, 13): self._heater_status = True - else: self._heater_status = False - if self.is_set(self.status_register, 11): self._humidity_tracking_alert = True - else: self._humidity_tracking_alert = False - if self.is_set(self.status_register, 10): self._temperature_tracking_alert = True - else: self._temperature_tracking_alert = False - if self.is_set(self.status_register, 4): self._system_reset_detected = True - else: self._system_reset_detected = False - if self.is_set(self.status_register, 1): self._command_status_successfully = True - else: self._command_status_successfully = False - - cl_fact_logger.get_instance().debug("Alert pending: %r" % self._alert_pending) - cl_fact_logger.get_instance().debug("Heater status: %r" % self._heater_status) - cl_fact_logger.get_instance().debug("Humidity tracking alert: %r" % self._humidity_tracking_alert) - cl_fact_logger.get_instance().debug("Temperature tracking alert: %r" % self._temperature_tracking_alert) - cl_fact_logger.get_instance().debug("System reset detected: %r" % self._system_reset_detected) - cl_fact_logger.get_instance().debug("Command status successfully %r" % self._command_status_successfully) - - # CRC Values - - status_register_crc = self._i2c_sensor.calculate_checksum(self.status_register) - localtime = time.asctime( time.localtime(time.time()) ) - sensor_crc = self.data0[2] - if hex(status_register_crc) != hex(sensor_crc): - cl_fact_logger.get_instance().debug("Local current time :", localtime) - cl_fact_logger.get_instance().debug("Status Register CRC calc is : %x " %status_register_crc) - cl_fact_logger.get_instance().debug("Status Register CRC real is : %x " %sensor_crc) - cl_fact_logger.get_instance().error("Status Register CRC Error") - - def is_set(self, x, n): # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - #return x & 2 ** n != 0 - - # a more bitwise- and performance-friendly version: - return (x & 1 << n != 0) + # Get the full status word + write = i2c_msg.write(self.o_address, self.SHT_CMD_STATUS) + self._i2c_bus.i2c_rdwr(write) + time.sleep(0.01) + read = i2c_msg.read(self.o_address, 3) + self._i2c_bus.i2c_rdwr(read) + time.sleep(0.01) + buf = list(read) + status = (buf[0] << 8) | buf[1] + + crc = self.sht_calc_crc(buf, 2) + cl_fact_logger.get_instance().debug(f"Status is {status:#04x}. CRC is {buf[2]:#02x}, calculated CRC is {crc:#02x}") + if (crc != buf[2]): + raise cx_measurement_error(f"CRC Error during read status. Status is {status:#04x}. CRC is {buf[2]:#02x}, calculated CRC is {crc:#02x}") + return status def get_current_data(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) repeat_count = 0 - repeat_count_max = 5 + repeat_count_max = 2 while repeat_count < repeat_count_max: try: - self._read_data() + buf = self.get_measure() + + if (self.sht_calc_crc(buf, 2) != buf[2]): + repeat_count += 1 + time.sleep(0.02) + continue + + hum_buf = buf[3:6] + if (self.sht_calc_crc(hum_buf, 2) != hum_buf[2]): + repeat_count += 1 + time.sleep(0.02) + continue - self._current_temperature = self._get_current_temperature() - self._current_humidity = self._get_current_humidity() + hum_offset = self.get_humidity_offset() + humidity_raw = (hum_buf[0] << 8) | hum_buf[1] # set the humidity + humidity_s = (humidity_raw / 65535.0 * 100.0) # convert the humidity + humidity_s += hum_offset # add offset + if (humidity_s > 100.0): + humidity_s = 100.0 + if (humidity_s < 0.0): + humidity_s = 0.0 + + temperature_raw = (buf[0] << 8) | buf[1] # set the temperature + temperature_s = 175.0 * temperature_raw / 65535.0 - 45.0 - cl_fact_logger.get_instance().debug("sht temperature : " + str(self._current_temperature)) - cl_fact_logger.get_instance().debug("sht humidity : " + str(self._current_humidity)) - self._dewpoint = super().get_dewpoint(self._current_temperature, self._current_humidity) - (temperature_dewpoint, humidity_absolute) = self._dewpoint + cl_fact_logger.get_instance().debug(f"sht temperature : {temperature_s:.2f}") + cl_fact_logger.get_instance().debug(f"sht humidity : {humidity_s:.1f}") + dewpoint = super().get_dewpoint(temperature_s, humidity_s) + (temperature_dewpoint, humidity_absolute) = dewpoint - self.measured_data = (self._current_temperature, self._current_humidity, temperature_dewpoint, humidity_absolute) + self.measured_data = (temperature_s, humidity_s, temperature_dewpoint, humidity_absolute) return(self.measured_data) except Exception as cx_error: - repeat_count = repeat_count + 1 + repeat_count += 1 if (repeat_count == 1): cl_fact_logger.get_instance().exception(cx_error) else: - cl_fact_logger.get_instance().error(f"Retry getting measurement from I2C device. Current retry count : {repeat_count}, max retry count : {repeat_count_max}") - - raise cx_measurement_error (_('Too many measurement errors occurred!')) - - - def _get_current_temperature(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - t_val = (self.data0[0]<<8) + self.data0[1] #convert the data - - Temperature_Celsius = (175.72 * self.t_val) / (2**16 - 1 ) - 45 #do the maths from datasheet - Temperature_Fahrenheit = (315.0 * self.t_val) / (2**16 - 1 ) - 49 #do the maths from datasheet - - cl_fact_logger.get_instance().debug("Temperature in Celsius is : %.2f C" %Temperature_Celsius) - cl_fact_logger.get_instance().debug("Temperature in Fahrenheit is : %.2f F" %Temperature_Fahrenheit) - - return(Temperature_Celsius) - - def _get_current_humidity(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - h_val = (self.data0[3] <<8) + self.data0[4] # Convert the data - - Humidity = (100.0 * self.h_val) / (2**16 - 1 ) - - cl_fact_logger.get_instance().debug("Relative Humidity is : %.2f %%RH" %Humidity) + cl_fact_logger.get_instance().error(f"Retry getting measurement from I2C device SHT. Current retry count : {repeat_count}, max retry count : {repeat_count_max}") - return(Humidity) - - def _write_to_db(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - super()._write_to_db() - pass + raise cx_measurement_error (_('Too many SHT measurement errors occurred!')) - def soft_reset(self): - """Performs Soft Reset on SHT chip""" - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + def cmd_soft_reset(self): + # Send the command to soft reset + write = i2c_msg.write(self.o_address, self.SHT_CMD_SOFTRESET) + self._i2c_bus.i2c_rdwr(write) + time.sleep(0.02) - msb_data = 0x30 - lsb_data = 0xA2 - #Write the sensor data - self._i2c_bus.write_byte_data(self._i2c_sensor.get_address(), msb_data, lsb_data) - self._send_i2c_start_command() - - def set_heading_on(self): - """Switch the heading on the sensor on""" - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self._i2c_bus.write(self._HEATER_ON) - pass - - def set_heading_off(self): - """Switch the heading on the sensor off""" - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self._i2c_bus.write(self._HEATER_OFF) - pass - - def execute(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self._write_to_db() - diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_sht3x.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht3x.py index 0781ab590..af0d336a4 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_sensor_sht3x.py +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht3x.py @@ -11,86 +11,63 @@ __email__ = "DerBurgermeister@pi-ager.org" __status__ = "Production" -#from abc import ABC, abstractmethod -import inspect +from abc import ABC, abstractmethod +# import inspect # import pi_ager_logging from main.pi_ager_cl_logger import cl_fact_logger -import time +# import time -from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type -from sensors.pi_ager_cl_i2c_bus import cl_fact_i2c_bus_logic -from sensors.pi_ager_cl_i2c_sensor_sht import cl_fact_i2c_sensor_sht +# from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type +# from sensors.pi_ager_cl_i2c_bus import cl_fact_i2c_bus_logic +# from sensors.pi_ager_cl_i2c_sensor_sht import cl_fact_i2c_sensor_sht from main.pi_ager_cx_exception import * -from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger -from sensors.pi_ager_cl_sensor import cl_sensor# -from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +# from sensors.pi_ager_cl_sensor import cl_sensor +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor from sensors.pi_ager_cl_sensor_sht import cl_sensor_sht -# global logger -# logger = pi_ager_logging.create_logger(__name__) - class cl_sensor_sht3x(cl_sensor_sht): - - + # i_active_sensor : 'MAIN' or 'SECOND' + # i_sensor_type : class cl_main_sensor_type or cl_second_sensor_type + # i_address : i2c address def __init__(self, i_sensor_type, i_active_sensor, i_address): - # logger.debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if "get_instance" not in inspect.stack()[1][3]: - raise cx_direct_call(self,"Please use factory class" ) - cl_fact_logger.get_instance().debug("i2c address is" + str(i_address)) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # if "get_instance" not in inspect.stack()[1][3]: + # raise cx_direct_call(self,"Please use factory class" ) + cl_fact_logger.get_instance().debug("i2c address is " + hex(i_address)) self.o_sensor_type = i_sensor_type self.o_address = i_address - super().__init__(i_active_sensor, self.o_sensor_type, self.o_address) + super().__init__(self.o_sensor_type, i_active_sensor, self.o_address) def get_current_data(self): - # logger.debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self.measured_data = super().get_current_data() return(self.measured_data) - - def execute(self): - # logger.debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - #self.get_current_data() - self._write_to_db() - -class th_sensor_sht3x(cl_sensor_sht3x): -# SUPPORTED_MAIN_SENSOR_TYPES = ["SHT75", "DHT11", "DHT22"] - NAME = 'Sensor SHT3x' - - def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self.get_type_raise = False - self._type = "SHT3x" - - def get_type(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if self.get_type_raise == True: - raise cx_Sensor_not_defined(self._type_ui) - return(self._type) - -class cl_fact_sensor_sht3x: - #fact_main_sensor_type = cl_fact_main_sensor_type() -# Only a singleton instance for main_sensor - #__o_sensor_type = fact_main_sensor_type.get_instance() +class cl_fact_sensor_sht3x(ABC): __o_instance = None __ot_instances = {} @classmethod def get_instance(self, i_sensor_type, i_active_sensor, i_address): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_logger.get_instance().debug("cl_fact_sensor_sht3x.get_instance") cl_fact_logger.get_instance().debug("Old sht3x __ot_instances = " + str(cl_fact_sensor_sht3x.__ot_instances)) - try: - cl_fact_sensor_sht3x.__o_instance = cl_fact_sensor_sht3x.__ot_instances.pop(i_active_sensor) - cl_fact_logger.get_instance().debug("sht3x __ot_instance for " + i_active_sensor + " = " + str(cl_fact_sensor_sht3x.__o_instance)) - except KeyError: - cl_fact_logger.get_instance().debug("sht3x __ot_instance not found for " + i_active_sensor) - cl_fact_sensor_sht3x.__o_instance = None + + cl_fact_sensor_sht3x.__o_instance = cl_fact_sensor_sht3x.__ot_instances.get(i_active_sensor) if cl_fact_sensor_sht3x.__o_instance is not None : cl_fact_logger.get_instance().debug("sht3x __ot_instance = " + str(cl_fact_sensor_sht3x.__o_instance)+ " Returning") return(cl_fact_sensor_sht3x.__o_instance) + +# try: +# cl_fact_sensor_sht3x.__o_instance = cl_fact_sensor_sht3x.__ot_instances.pop(i_active_sensor) +# cl_fact_logger.get_instance().debug("sht3x __ot_instance for " + i_active_sensor + " = " + str(cl_fact_sensor_sht3x.__o_instance)) +# except KeyError: +# cl_fact_logger.get_instance().debug("sht3x __ot_instance not found for " + i_active_sensor) +# cl_fact_sensor_sht3x.__o_instance = None +# if cl_fact_sensor_sht3x.__o_instance is not None : +# cl_fact_logger.get_instance().debug("sht3x __ot_instance = " + str(cl_fact_sensor_sht3x.__o_instance)+ " Returning") +# return(cl_fact_sensor_sht3x.__o_instance) cl_fact_sensor_sht3x.__o_instance = cl_sensor_sht3x(i_sensor_type, i_active_sensor, i_address) cl_fact_logger.get_instance().debug("sht3x __ot_instance " + i_active_sensor + str(cl_fact_sensor_sht3x.__o_instance) + " created for " ) @@ -101,10 +78,10 @@ def get_instance(self, i_sensor_type, i_active_sensor, i_address): @classmethod def set_instance(self, i_active_sensor, i_instance): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_sensor_sht3x.__o_instance = i_instance def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) pass diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_sht4.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht4.py new file mode 100644 index 000000000..d7f6e8047 --- /dev/null +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht4.py @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- + +"""This class is for handling the SHT sensors SHT4x-A/B/C with i2c bus interface from sensirion.""" + +#from abc import ABC, abstractmethod +from main.pi_ager_cl_logger import cl_fact_logger +from smbus2 import i2c_msg +import time +from sensors.pi_ager_cl_i2c_bus import cl_fact_i2c_bus_logic +from main.pi_ager_cx_exception import * +from sensors.pi_ager_cl_sensor import cl_sensor + + +class cl_sensor_sht4(cl_sensor): + SHT_CMD_SOFTRESET = [0x94] + SHT_CMD_MEASURE = [0xfd] + + # Initial value. Equal to bit negation the first data + CRC_INIT = 0xFF + # CRC polynomial G(x) = x8 + x5 + x4 + 1 + CRC_POLY = 0x31 + + # i_active_sensor : 'MAIN' or 'SECOND' + # i_sensor_type : class cl_main_sensor_type or cl_second_sensor_type + # i_address : i2c address + def __init__(self, i_sensor_type, i_active_sensor, i_address): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + if i_address is not None: + cl_fact_logger.get_instance().debug("i2c address is " + hex(i_address)) + + self.repeat_count_max = 3 + + self.o_address = i_address + self.o_sensor_type = i_sensor_type + self.o_active_sensor= i_active_sensor + + super().__init__(self.o_sensor_type) + + self._i2c_bus = cl_fact_i2c_bus_logic.get_instance().get_i2c_bus() + self.cmd_soft_reset() + time.sleep(0.02) +# cl_fact_logger.get_instance().debug(self._i2c_bus) +# self._i2c_sensor = cl_fact_i2c_sensor_sht.get_instance(self.o_active_sensor, self._i2c_bus, self.o_address) + + + def sht_calc_crc(self, data, len): + crc = self.CRC_INIT + + for byte in range(len): # len times + crc ^= data[byte] # xor byte + for i in range(8): # one byte + if ((crc & 0x80) != 0): # if high + crc = (crc << 1) ^ self.CRC_POLY # xor 0x31 + else: + crc = crc << 1 # skip + + return crc & 0xff + + def cmd_measure(self): + # Send the command to measure + write = i2c_msg.write(self.o_address, self.SHT_CMD_MEASURE) + self._i2c_bus.i2c_rdwr(write) + time.sleep(0.02) #This is so the sensor has time to perform the measurement and write its registers before you read it + + def get_measure(self): + # Get the full measure + self.cmd_measure() + read = i2c_msg.read(self.o_address, 6) + self._i2c_bus.i2c_rdwr(read) + buf = list(read) + return buf + + def get_current_data(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + repeat_count = 0 + repeat_count_max = 2 + while repeat_count < repeat_count_max: + try: + buf = self.get_measure() + + if (self.sht_calc_crc(buf, 2) != buf[2]): + repeat_count += 1 + time.sleep(0.02) + continue + + hum_buf = buf[3:6] + if (self.sht_calc_crc(hum_buf, 2) != hum_buf[2]): + repeat_count += 1 + time.sleep(0.02) + continue + + hum_offset = self.get_humidity_offset() + humidity_raw = (hum_buf[0] << 8) | hum_buf[1] # set the humidity + humidity_s = (humidity_raw / 65535.0 * 125.0 - 6.0) # convert the humidity + humidity_s += hum_offset + if (humidity_s > 100.0): + humidity_s = 100.0 + if (humidity_s < 0.0): + humidity_s = 0.0 + + temperature_raw = (buf[0] << 8) | buf[1] # set the temperature + temperature_s = 175.0 * temperature_raw / 65535.0 - 45.0 + + cl_fact_logger.get_instance().debug(f"sht temperature : {temperature_s:.2f}") + cl_fact_logger.get_instance().debug(f"sht humidity : {humidity_s:.1f}") + dewpoint = super().get_dewpoint(temperature_s, humidity_s) + (temperature_dewpoint, humidity_absolute) = dewpoint + + self.measured_data = (temperature_s, humidity_s, temperature_dewpoint, humidity_absolute) + return(self.measured_data) + + except Exception as cx_error: + repeat_count += 1 + if (repeat_count == 1): + cl_fact_logger.get_instance().exception(cx_error) + else: + cl_fact_logger.get_instance().error(f"Retry getting measurement from I2C device SHT. Current retry count : {repeat_count}, max retry count : {repeat_count_max}") + + raise cx_measurement_error (_('Too many SHT measurement errors occurred!')) + + def cmd_soft_reset(self): + # Send the command to soft reset + write = i2c_msg.write(self.o_address, self.SHT_CMD_SOFTRESET) + self._i2c_bus.i2c_rdwr(write) + time.sleep(0.02) + diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_sht4x.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht4x.py new file mode 100644 index 000000000..b8a83e51c --- /dev/null +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht4x.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +"""This class is for handling the SHT4x sensor from sensirion.""" + +from abc import ABC, abstractmethod +# import inspect +# import pi_ager_logging +from main.pi_ager_cl_logger import cl_fact_logger +# import time + +from main.pi_ager_cx_exception import * +from sensors.pi_ager_cl_sensor_sht4 import cl_sensor_sht4 + +class cl_sensor_sht4x(cl_sensor_sht4): + # i_active_sensor : 'MAIN' or 'SECOND' + # i_sensor_type : class cl_main_sensor_type or cl_second_sensor_type + # i_address : i2c address + def __init__(self, i_sensor_type, i_active_sensor, i_address): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # if "get_instance" not in inspect.stack()[1][3]: + # raise cx_direct_call(self,"Please use factory class" ) + cl_fact_logger.get_instance().debug("i2c address is " + hex(i_address)) + self.o_sensor_type = i_sensor_type + self.o_address = i_address + + super().__init__(self.o_sensor_type, i_active_sensor, self.o_address) + + def get_current_data(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + self.measured_data = super().get_current_data() + return(self.measured_data) + +class cl_fact_sensor_sht4x(ABC): + __o_instance = None + __ot_instances = {} + @classmethod + def get_instance(self, i_sensor_type, i_active_sensor, i_address): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + cl_fact_logger.get_instance().debug("cl_fact_sensor_sht4x.get_instance") + cl_fact_logger.get_instance().debug("Old sht4x __ot_instances = " + str(cl_fact_sensor_sht4x.__ot_instances)) + + cl_fact_sensor_sht4x.__o_instance = cl_fact_sensor_sht4x.__ot_instances.get(i_active_sensor) + if cl_fact_sensor_sht4x.__o_instance is not None : + cl_fact_logger.get_instance().debug("sht4x __ot_instance = " + str(cl_fact_sensor_sht4x.__o_instance)+ " Returning") + return(cl_fact_sensor_sht4x.__o_instance) + +# try: +# cl_fact_sensor_sht3x.__o_instance = cl_fact_sensor_sht3x.__ot_instances.pop(i_active_sensor) +# cl_fact_logger.get_instance().debug("sht3x __ot_instance for " + i_active_sensor + " = " + str(cl_fact_sensor_sht3x.__o_instance)) +# except KeyError: +# cl_fact_logger.get_instance().debug("sht3x __ot_instance not found for " + i_active_sensor) +# cl_fact_sensor_sht3x.__o_instance = None +# if cl_fact_sensor_sht3x.__o_instance is not None : +# cl_fact_logger.get_instance().debug("sht3x __ot_instance = " + str(cl_fact_sensor_sht3x.__o_instance)+ " Returning") +# return(cl_fact_sensor_sht3x.__o_instance) + + cl_fact_sensor_sht4x.__o_instance = cl_sensor_sht4x(i_sensor_type, i_active_sensor, i_address) + cl_fact_logger.get_instance().debug("sht4x __ot_instance " + i_active_sensor + str(cl_fact_sensor_sht4x.__o_instance) + " created for " ) + line = {i_active_sensor:cl_fact_sensor_sht4x.__o_instance} + cl_fact_sensor_sht4x.__ot_instances.update(line) + cl_fact_logger.get_instance().debug("New sht4x __ot_instances = " + str(cl_fact_sensor_sht4x.__ot_instances)) + return(cl_fact_sensor_sht4x.__o_instance) + + @classmethod + def set_instance(self, i_active_sensor, i_instance): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + cl_fact_sensor_sht4x.__o_instance = i_instance + + def __init__(self): + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + pass + diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_sht75.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht75.py index 1f53f94c3..dfbe51a47 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_sensor_sht75.py +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht75.py @@ -11,45 +11,48 @@ __email__ = "DerBurgermeister@pi-ager.org" __status__ = "Production" -import inspect +from abc import ABC, abstractmethod from main.pi_ager_cl_logger import cl_fact_logger -import time +# import time import pi_sht1x import pi_ager_gpio_config -from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type +# from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type from main.pi_ager_cx_exception import * -from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger from sensors.pi_ager_cl_sensor import cl_sensor -from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor class cl_sensor_sht75(cl_sensor): def __init__(self, i_sensor_type, i_active_sensor): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if "get_instance" not in inspect.stack()[1][3]: - raise cx_direct_call(self,"Please use factory class" ) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + self.o_sensor_type = i_sensor_type - self._error_counter = 0 - self._max_errors = 5 - self._old_temperature = 0 + self.o_active_sensor = i_active_sensor + self._current_temperature = 0 - self._temperature_dewpoint = 0 - self._humidity_absolute = 0 - self._old_humidity = 0 self._current_humidity = 0 + self._max_errors = 5 self._sensor_sht = pi_sht1x.SHT1x(pi_ager_gpio_config.gpio_sensor_data, pi_ager_gpio_config.gpio_sensor_sync, gpio_mode=pi_ager_gpio_config.board_mode) - def get_current_data(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self.delete_error_counter() + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + self._error_counter = 0 + while self._error_counter < self._max_errors: try: + hum_offset = self.get_humidity_offset() self._current_temperature = self._get_current_temperature() - self._current_humidity = self._get_current_humidity() + humidity_s = self._get_current_humidity() + hum_offset + if (humidity_s > 100.0): + humidity_s = 100.0 + if (humidity_s < 0.0): + humidity_s = 0.0 + self._current_humidity = humidity_s + self._dewpoint = super().get_dewpoint(self._current_temperature, self._current_humidity) cl_fact_logger.get_instance().debug("sht75 temperature : %.2f °C" % self._current_temperature) cl_fact_logger.get_instance().debug("sht75 humidity : %.2f %%RH" % self._current_humidity) @@ -66,99 +69,42 @@ def get_current_data(self): else: cl_fact_logger.get_instance().error(f"Retry getting measurement from SHT75. Current retry count : {self._error_counter}, max retry count : {self._max_errors}") -# self.delete_error_counter() cl_fact_logger.get_instance().debug('Too many measurement errors occurred!') raise cx_measurement_error(_('Too many measurement errors occurred!')) def _get_current_temperature(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self._sensor_sht.read_temperature() Temperature_Celsius = self._sensor_sht.temperature_celsius - Temperature_Fahrenheit = self._sensor_sht.temperature_celsius * 9/5 + 32 + # Temperature_Fahrenheit = self._sensor_sht.temperature_celsius * 9/5 + 32 # cl_fact_logger.get_instance().debug("Temperature in Celsius is : %.2f °C" %Temperature_Celsius) # cl_fact_logger.get_instance().debug("Temperature in Fahrenheit is : %.2f F" %Temperature_Fahrenheit) self._current_temperature = Temperature_Celsius - if self._old_temperature is None: - self._old_temperature = 0 - else: - self._old_temperature = self._current_temperature - return(self._current_temperature) def _get_current_humidity(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self._sensor_sht.read_humidity() - Humidity = self._sensor_sht.humidity # cl_fact_logger.get_instance().debug("Relative Humidity is : %.2f %%RH" %Humidity) self._current_humidity = Humidity - - if self._old_humidity is None: - self._old_humidity = 0 - else: - self._old_humidity = self._current_humidity - return(self._current_humidity) - - def _write_to_db(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - super()._write_to_db() - pass - def soft_reset(self): - """Performs Soft Reset on SHT chip""" - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - def set_heading_on(self): - """Switch the heading on the sensor on""" - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - - def set_heading_off(self): - """Switch the heading on the sensor off""" - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - - - def execute(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - #self.get_current_data() - self._write_to_db() - -class th_sensor_sht75(cl_sensor_sht75): -# SUPPORTED_MAIN_SENSOR_TYPES = ["SHT75", "DHT11", "DHT22"] - NAME = 'Main_sensor' - - - def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self.get_type_raise = False - self._type = "SHT75" - - def get_type(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if self.get_type_raise == True: - raise cx_Sensor_not_defined(self._type_ui) - return(self._type) - - -class cl_fact_sensor_sht75: - #fact_main_sensor_type = cl_fact_main_sensor_type() -# Only a singleton instance for main_sensor - #__o_sensor_type = fact_main_sensor_type.get_instance() +class cl_fact_sensor_sht75(ABC): __o_instance = None @classmethod def get_instance(self, i_sensor_type, i_active_sensor): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) if cl_fact_sensor_sht75.__o_instance is not None: return(cl_fact_sensor_sht75.__o_instance) cl_fact_sensor_sht75.__o_instance = cl_sensor_sht75(i_sensor_type, i_active_sensor) @@ -166,11 +112,11 @@ def get_instance(self, i_sensor_type, i_active_sensor): @classmethod def set_instance(self, i_instance): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_sensor_sht75.__o_instance = i_instance def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) pass diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_sht85.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht85.py index 69444934b..481bbd540 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_sensor_sht85.py +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_sht85.py @@ -11,98 +11,58 @@ __email__ = "DerBurgermeister@pi-ager.org" __status__ = "Production" -#from abc import ABC, abstractmethod +from abc import ABC, abstractmethod import inspect # import pi_ager_logging from main.pi_ager_cl_logger import cl_fact_logger import time -from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type -from sensors.pi_ager_cl_i2c_bus import cl_fact_i2c_bus_logic -from sensors.pi_ager_cl_i2c_sensor_sht import cl_fact_i2c_sensor_sht +# from sensors.pi_ager_cl_sensor_type import cl_fact_main_sensor_type +# from sensors.pi_ager_cl_i2c_bus import cl_fact_i2c_bus_logic +# from sensors.pi_ager_cl_i2c_sensor_sht import cl_fact_i2c_sensor_sht from main.pi_ager_cx_exception import * -from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger -from sensors.pi_ager_cl_sensor import cl_sensor# -from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor +# from messenger.pi_ager_cl_messenger import cl_fact_logic_messenger +# from sensors.pi_ager_cl_sensor import cl_sensor +# from sensors.pi_ager_cl_ab_sensor import cl_ab_sensor from sensors.pi_ager_cl_sensor_sht import cl_sensor_sht -# global logger -# logger = pi_ager_logging.create_logger(__name__) - class cl_sensor_sht85(cl_sensor_sht): - + # i_active_sensor : 'MAIN' or 'SECOND' + # i_sensor_type : class cl_main_sensor_type or cl_second_sensor_type + # i_address : i2c address def __init__(self, i_sensor_type, i_active_sensor, i_address): - # logger.debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if "get_instance" not in inspect.stack()[1][3]: - raise cx_direct_call(self,"Please use factory class" ) - cl_fact_logger.get_instance().debug("i2c address is" + str(i_address)) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # if "get_instance" not in inspect.stack()[1][3]: + # raise cx_direct_call(self,"Please use factory class" ) + cl_fact_logger.get_instance().debug("i2c address is" + (str(i_address) if i_address == None else hex(i_address))) self.o_sensor_type = i_sensor_type self.o_address = i_address - super().__init__(i_active_sensor, self.o_sensor_type, self.o_address) + super().__init__(self.o_sensor_type, i_active_sensor, self.o_address) def get_current_data(self): - # logger.debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self.measured_data = super().get_current_data() return(self.measured_data) - - def execute(self): - # logger.debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - #self.get_current_data() - self._write_to_db() - -class th_sensor_sht85(cl_sensor_sht85): -# SUPPORTED_MAIN_SENSOR_TYPES = ["SHT75", "DHT11", "DHT22"] - NAME = 'Sensor SHT85' - - def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - self.get_type_raise = False - self._type = "SHT85" - - def get_type(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if self.get_type_raise == True: - raise cx_Sensor_not_defined(self._type_ui) - return(self._type) - -class cl_fact_sensor_sht85: - #fact_main_sensor_type = cl_fact_main_sensor_type() -# Only a singleton instance for main_sensor - #__o_sensor_type = fact_main_sensor_type.get_instance() +class cl_fact_sensor_sht85(ABC): __o_instance = None - __ot_instances = {} + @classmethod def get_instance(self, i_sensor_type, i_active_sensor, i_address): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_logger.get_instance().debug("cl_fact_sensor_sht85.get_instance") - try: - cl_fact_sensor_sht85.__o_instance = cl_fact_sensor_sht85.__ot_instances.pop(i_active_sensor) - cl_fact_logger.get_instance().debug("__ot_instance for " + i_active_sensor + " = " + str(cl_fact_sensor_sht85.__o_instance)) - except KeyError: - cl_fact_logger.get_instance().debug("__ot_instance not found for " + i_active_sensor) - cl_fact_sensor_sht85.__o_instance = None - if cl_fact_sensor_sht85.__o_instance is not None : - cl_fact_logger.get_instance().debug("Returning __ot_instance = " + str(cl_fact_sensor_sht85.__o_instance)) - return(cl_fact_sensor_sht85.__o_instance) - + if cl_fact_sensor_sht85.__o_instance is not None: + return(cl_fact_sensor_sht85.__ot_instance) cl_fact_sensor_sht85.__o_instance = cl_sensor_sht85(i_sensor_type, i_active_sensor, i_address) - cl_fact_logger.get_instance().debug("__ot_instance " + str(cl_fact_sensor_sht85.__o_instance) + " created for " + i_active_sensor) - line = {i_active_sensor:cl_fact_sensor_sht85.__o_instance} - cl_fact_sensor_sht85.__ot_instances.update(line) - cl_fact_logger.get_instance().debug("__ot_instances = " + str(cl_fact_sensor_sht85.__ot_instances)) return(cl_fact_sensor_sht85.__o_instance) @classmethod def set_instance(self, i_active_sensor, i_instance): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) cl_fact_sensor_sht85.__o_instance = i_instance def __init__(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) pass diff --git a/opt/pi-ager/sensors/pi_ager_cl_sensor_type.py b/opt/pi-ager/sensors/pi_ager_cl_sensor_type.py index 29dba7fa9..bbea559ce 100644 --- a/opt/pi-ager/sensors/pi_ager_cl_sensor_type.py +++ b/opt/pi-ager/sensors/pi_ager_cl_sensor_type.py @@ -2,43 +2,23 @@ """This class is for handling main sensor types.""" -__author__ = "Claus Fischer" -__copyright__ = "Copyright 2019, The Pi-Ager Project" -__credits__ = ["Claus Fischer"] -__license__ = "GPL" -__version__ = "1.0.0" -__maintainer__ = "Claus Fischer" -__email__ = "DerBurgermeister@pi-ager.org" -__status__ = "Production" -from abc import ABC +from abc import ABC, abstractmethod import inspect from main.pi_ager_cx_exception import * -from main.pi_ager_cl_logger import * -# import pi_ager_logging +# from main.pi_ager_cl_logger import * from main.pi_ager_cl_logger import cl_fact_logger import pi_ager_database import pi_ager_names - -# global logger -# logger = pi_ager_logging.create_logger(__name__) - class cl_main_sensor_type: - __SUPPORTED_MAIN_SENSOR_TYPES = {1: "DHT11", - 2: "DHT22", - 3: "SHT75", - 4: "SHT85", - 5: "SHT3x"} __NAME = 'Main_sensor' _type = 0 _type_ui = "" def __init__(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # frame,filename,line_number,function_name,lines,index = inspect.stack()[1] if "get_instance" not in inspect.stack()[1][3]: raise cx_direct_call("Please use factory class") -# if direct: -# raise cx_direct_call(self, "Please use factory class") try: self._read_sensor_type() @@ -46,104 +26,69 @@ def __init__(self): cl_fact_logger.get_instance().debug('Sensor type not found!') raise original_error -# cl_main_sensor_type.__SUPPORTED_MAIN_SENSOR_TYPES = ["SHT75", "DHT11", "DHT22"] -# cl_main_sensor_type.__NAME = 'Main_sensor' - - def _get_type_ui(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) if self._is_valid() == False: raise cx_Sensor_not_defined(self._type_ui) - self._type_ui = cl_main_sensor_type.__SUPPORTED_MAIN_SENSOR_TYPES[self._type] - - + self._type_ui = pi_ager_names.SUPPORTED_MAIN_SENSOR_TYPES[self._type] return(self._type_ui) def _is_valid(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if cl_main_sensor_type.__SUPPORTED_MAIN_SENSOR_TYPES[self._type]: -# if self._type in cl_main_sensor_type.__SUPPORTED_MAIN_SENSOR_TYPES: + if pi_ager_names.SUPPORTED_MAIN_SENSOR_TYPES[self._type]: return(True) else: return(False) - def _read_sensor_type(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self._type = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.sensortype_key)) - # logger.info('Sensor number is: ' + str(self._type)) cl_fact_logger.get_instance().debug('Sensor number is: ' + str(self._type)) if self._is_valid() == False: raise cx_Sensor_not_defined(self._type_ui) self._type_ui = self._get_type_ui() cl_fact_logger.get_instance().debug("Sensor type is: " + str(self._type_ui)) - return() def get_sensor_type(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) return(self._type) def get_sensor_type_ui(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) return(self._type_ui) def get_name(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) return(cl_main_sensor_type.__NAME) def get_supported_types(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) # print('[%s]' % ', '.join(map(str, cl_main_sensor_type.__SUPPORTED_MAIN_SENSOR_TYPES ))) pass -class cl_second_sensor_type(cl_main_sensor_type): - __SUPPORTED_SECOND_SENSOR_TYPES = { 0: "disabled", - 4: "SHT85", - 5: "SHT3x", - 6: "MiThermometer"} +class cl_second_sensor_type(): __NAME = 'Second_sensor' _type = 0 _type_ui = "" - """ def __init__(self): - # logger.debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) + # frame,filename,line_number,function_name,lines,index = inspect.stack()[1] if "get_instance" not in inspect.stack()[1][3]: raise cx_direct_call("Please use factory class") -# if direct: -# raise cx_direct_call(self, "Please use factory class") try: self._read_sensor_type() except Exception as original_error: - # logger.debug('Sensor type not found!') cl_fact_logger.get_instance().debug('Sensor type not found!') raise original_error -# cl_main_sensor_type.__SUPPORTED_MAIN_SENSOR_TYPES = ["SHT75", "DHT11", "DHT22"] -# cl_main_sensor_type.__NAME = 'Main_sensor' - """ def _get_type_ui(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) if self._is_valid() == False: raise cx_Sensor_not_defined(self._type_ui) - self._type_ui = cl_second_sensor_type.__SUPPORTED_SECOND_SENSOR_TYPES[self._type] - - + self._type_ui = pi_ager_names.SUPPORTED_SECOND_SENSOR_TYPES[self._type] return(self._type_ui) + def _is_valid(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - if cl_second_sensor_type.__SUPPORTED_SECOND_SENSOR_TYPES[self._type]: -# if self._type in cl_main_sensor_type.__SUPPORTED_MAIN_SENSOR_TYPES: + if pi_ager_names.SUPPORTED_SECOND_SENSOR_TYPES[self._type]: return(True) else: return(False) - def _read_sensor_type(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) self._type = int(pi_ager_database.get_table_value(pi_ager_names.config_settings_table, pi_ager_names.sensorsecondtype_key)) cl_fact_logger.get_instance().debug('Second Sensor number is: ' + str(self._type)) @@ -151,58 +96,18 @@ def _read_sensor_type(self): raise cx_Sensor_not_defined(self._type_ui) self._type_ui = self._get_type_ui() cl_fact_logger.get_instance().debug("Second Sensor type is: " + str(self._type_ui)) - return() - """ - def get_sensor_type(self): - # logger.debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - return(self._type) + def get_sensor_type(self): + return(self._type) + def get_sensor_type_ui(self): - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - # logger.debug(cl_fact_logger.get_instance().me()) return(self._type_ui) - def get_name(self): - # logger.debug(cl_fact_logger.get_instance().me()) - cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - return(cl_main_sensor_type.__NAME) - """ def get_supported_types(self): - # cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) # print('[%s]' % ', '.join(map(str, cl_second_sensor_type.__SUPPORTED_SECOND_SENSOR_TYPES ))) pass - - -class th_main_sensor_type(cl_main_sensor_type): - - __NAME = 'Main_sensor' - def __init__(self): - self._type = 3 #SHT75 - self._type_ui = "SHT75" - self.is_valid = True - - pass - - def _is_valid(self): - if self.is_valid == True: - return(True) - else: - return(False) - - def get_type(self): - if self.is_valid == False: - raise cx_Sensor_not_defined("This sensor is not defined") - return(self._type) - def _get_type_ui(self): - return(self._type_ui) - def get_name(self): - #cl_fact_logger.get_instance().debug(cl_fact_logger.get_instance().me()) - return(th_main_sensor_type.__NAME) - - class cl_fact_main_sensor_type(ABC): __o_instance = None diff --git a/usr/bin/nodogsplash b/usr/bin/nodogsplash new file mode 100644 index 000000000..c1c7b3d97 Binary files /dev/null and b/usr/bin/nodogsplash differ diff --git a/usr/local/bin/image-shrink.sh b/usr/local/bin/image-shrink.sh new file mode 100644 index 000000000..5364ded17 --- /dev/null +++ b/usr/local/bin/image-shrink.sh @@ -0,0 +1,144 @@ +#!/bin/bash + +mkloop() +{ + LOOP="$(losetup -f --show -P "${IMGFILE}")" + if [ $? -ne 0 ]; then + errexit "Unable to create loop device" + fi +} + +rmloop() +{ + losetup -d "${LOOP}" +} + +fsckerr() +{ + rmloop + errexit "Filesystem appears corrupted "$1" resize2fs" +} + +errexit() +{ + echo "" + echo -e "\e[91m$1\e[39m" + echo "" + exit 1 +} + +if [ $(id -u) -ne 0 ]; then + errexit "$0 must be run as root user" +fi +PGMNAME="$(basename $0)" +for PID in $(pidof -x -o %PPID "${PGMNAME}"); do + if [ ${PID} -ne $$ ]; then + errexit "${PGMNAME} is already running" + fi +done +gdisk -l "${DEVICE}" &> /dev/null +if [ $? -eq 127 ]; then + echo "" + echo "gdisk not installed. Installing gdisk" + echo "" + apt-get update + apt-get install gdisk +fi +IMGFILE="$1" +if [ "${IMGFILE}" = "" ]; then + errexit "Usage: $0 imagefile [Additional MB]" +fi +if [ ! -f "${IMGFILE}" ] || [ ! -s "${IMGFILE}" ]; then + errexit "${IMGFILE} is missing or empty" +fi +mkloop +FS_TYPE=$(blkid "${LOOP}p2" | sed -n 's|^.*TYPE="\(\S\+\)".*|\1|p') +rmloop +if [ "${FS_TYPE}" = "f2fs" ]; then + errexit "Cannot shrink F2FS filesystem" +fi +answer="$2" +if [[ ! "${answer}" =~ ^[0-9]+$ ]]; then + errexit "You must specify additional MB." +fi +while [ "${answer:0:1}" = "0" ]; do + answer="${answer:1}" +done +if [ ${#answer} -eq 0 ]; then + answer=0 +fi +ADDMB=${answer} +echo "" +INFO="$(sfdisk -d "${IMGFILE}")" +BOOTBEG=$(sed -n "s|^${IMGFILE}1.*start=\s*\([0-9]\+\).*$|\1|p" <<< "${INFO}") +BOOTEND=$((${BOOTBEG} + $(sed -n "s|^${IMGFILE}1.*size=\s*\([0-9]\+\).*$|\1|p" <<< "${INFO}") - 1)) +ROOTBEG=$(sed -n "s|^${IMGFILE}2.*start=\s*\([0-9]\+\).*$|\1|p" <<< "${INFO}") +PARTUUID_1="$(sed -n "s|^${IMGFILE}1.*uuid=\(\S\+\).*$|\1|p" <<< "${INFO}")" +PARTUUID_2="$(sed -n "s|^${IMGFILE}2.*uuid=\(\S\+\).*$|\1|p" <<< "${INFO}")" +PTUUID="$(sed -n "s|^label-id: \(\S\+\).*$|\1|p" <<< "${INFO}")" +PTTYPE="$(sed -n "s|^label: \(\S\+\).*$|\1|p" <<< "${INFO}")" +if [[ "${PTTYPE}" != "dos" && "${PTTYPE}" != "gpt" ]]; then + errexit "Unsupported partition table type: ${PTTYPE}" +fi +mkloop +e2fsck -f -p -v "${LOOP}p2" +if [ $? -gt 2 ]; then + fsckerr "before" +fi +echo "" +resize2fs -f -M "${LOOP}p2" +resize2fs -f -M "${LOOP}p2" +resize2fs -f -M "${LOOP}p2" +e2fsck -f -n "${LOOP}p2" +if [ $? -ne 0 ]; then + fsckerr "after" +fi +INFO="$(tune2fs -l "${LOOP}p2" 2>/dev/null)" +rmloop +NEWSIZE=$(sed -n 's|^Block count:\s*\(.*\)|\1|p' <<< "${INFO}") +BLKSIZE=$(sed -n 's|^Block size:\s*\(.*\)|\1|p' <<< "${INFO}") +NEWEND=$((${ROOTBEG} + (${NEWSIZE} * (${BLKSIZE} / 512)) + ((${ADDMB} * 1024 * 1024) / 512) - 1)) +if [ "${PTTYPE}" = "gpt" ]; then + ((NEWEND += 33)) +fi +truncate -s $(((${NEWEND} + 1) * 512)) "${IMGFILE}" +if [ "${PTTYPE}" = "dos" ]; then + sfdisk --delete "${IMGFILE}" 2 > /dev/null + echo "${ROOTBEG},+" | sfdisk -N2 "${IMGFILE}" &> /dev/null +else + sgdisk -Z "${IMGFILE}" &> /dev/null + sgdisk -n 1:${BOOTBEG}:${BOOTEND} "${IMGFILE}" > /dev/null + sgdisk -t 1:0700 "${IMGFILE}" > /dev/null + sgdisk -n 2:${ROOTBEG}:0 "${IMGFILE}" > /dev/null + sgdisk -t 2:8300 "${IMGFILE}" > /dev/null + sgdisk -u 1:"${PARTUUID_1}" "${IMGFILE}" > /dev/null + sgdisk -u 2:"${PARTUUID_2}" "${IMGFILE}" > /dev/null + sgdisk -U "${PTUUID}" "${IMGFILE}" > /dev/null + gdisk "${IMGFILE}" < /dev/null +r +h +1 +n +0c +n +n +w +y +EOF +fi +if [ ${ADDMB} -ne 0 ]; then + echo "" + mkloop + e2fsck -f -n "${LOOP}p2" + if [ $? -ne 0 ]; then + fsckerr "before" + fi + echo "" + resize2fs -f "${LOOP}p2" + e2fsck -f -n "${LOOP}p2" + if [ $? -ne 0 ]; then + fsckerr "after" + fi + rmloop +fi +echo "" diff --git a/usr/local/bin/modify_nmconnection b/usr/local/bin/modify_nmconnection new file mode 100644 index 000000000..c8f4ffd5c --- /dev/null +++ b/usr/local/bin/modify_nmconnection @@ -0,0 +1,45 @@ +#!/usr/bin/python3 +import sys + +def main(): + + if len(sys.argv) != 6: + print("Usage must equal [filename] [ssid] [psk] [uuid] [timestamp]") + sys.exit(1) + + filename = sys.argv[1] + ssid = sys.argv[2] + psk = sys.argv[3] + uuid = sys.argv[4] + timestamp = sys.argv[5] + # filename = "test.nmconnection" + # print("ssid : " + ssid) + # print("psk : " + psk) + # print("uuid : " + uuid) + # print("timestamp : " + timestamp) + + reading_file = open(filename, "r") + + new_file_content = "" + for line in reading_file: + stripped_line = line.strip() + + if ("ssid=" in stripped_line): + new_line = "ssid=" + ssid + elif ("psk=" in stripped_line): + new_line = "psk=" + psk + elif ("uuid=" in stripped_line): + new_line = "uuid=" + uuid + elif ("timestamp=" in stripped_line): + new_line = "timestamp=" + timestamp + else: + new_line = stripped_line + new_file_content += new_line +"\n" + reading_file.close() + + writing_file = open(filename, "w") + writing_file.write(new_file_content) + writing_file.close() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/usr/local/bin/nextion-fw-upload b/usr/local/bin/nextion-fw-upload new file mode 100644 index 000000000..7ba6a4ce3 --- /dev/null +++ b/usr/local/bin/nextion-fw-upload @@ -0,0 +1,8 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from nextion.console_scripts.upload_firmware import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/usr/local/bin/pi-ager_backup.sh b/usr/local/bin/pi-ager_backup.sh index 4ded41d98..88b1c4725 100644 --- a/usr/local/bin/pi-ager_backup.sh +++ b/usr/local/bin/pi-ager_backup.sh @@ -152,8 +152,11 @@ array=(${NFSVOL//:/ }) serverIP=${array[0]} echo "NFS IP address = $serverIP" localIP=$(hostname -I) -#remove last space character -localIP=${localIP// /} +#remove space characters +#localIP=${localIP// /} +# with RPIhotspot we have two addresses, first address is station address, second address is AP address +array=(${localIP// / }) +localIP=${array[0]} echo "Local IP address = $localIP" echo "check if nfs Server IP address has correct format" @@ -204,30 +207,20 @@ if [ -d "$NFSMOUNT" ] fi #Überprüfen ob PiShrink aktuell ist sonst herunterladen -echo "check if PiShrink exists." -echo "Checking..." -online_md5="$(curl -sL https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh | md5sum | cut -d ' ' -f 1)" -local_md5="$(md5sum "/usr/local/bin/pishrink.sh" | cut -d ' ' -f 1)" -if [[ "$online_md5" == "$local_md5" ]] - then - echo "PiShrink is the latest version!" - else - echo "Installing PiShrink!" - wget -N https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh - chmod +x pishrink.sh - mv pishrink.sh /usr/local/bin - echo "PiShrink installed." -fi - -#if [ -x /usr/local/bin/pishrink.sh ] +# echo "check if PiShrink exists." +# echo "Checking..." +# online_md5="$(curl -sL https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh | md5sum | cut -d ' ' -f 1)" +# local_md5="$(md5sum "/usr/local/bin/pishrink.sh" | cut -d ' ' -f 1)" +# if [[ "$online_md5" == "$local_md5" ]] # then -# echo "PiShrink ist vorhanden" -# else -# echo "PiShrink wird geladen!" +# echo "PiShrink is the latest version!" +# else +# echo "Installing PiShrink!" # wget -N https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh # chmod +x pishrink.sh -# sudo mv pishrink.sh /usr/local/bin -#fi +# mv pishrink.sh /usr/local/bin +# echo "PiShrink installed." +# fi DIR=$NFSMOUNT @@ -254,7 +247,7 @@ if [ -n "$NFSOPT" ] mount -t nfs4 $NFSVOL $NFSMOUNT mountstatus=$? fi -# exit 1 + if [ $mountstatus -ne 0 ]; then echo "Error $mountstatus during mount NFS Volume $NFSVOL. Backup stopped." exit 1 @@ -317,9 +310,6 @@ if [[ "$ACCESS" == "no" ]]; then echo "$u can write into $DIR mapped to $NFSVOL, Backup continues." fi -# umount $NFSMOUNT -# exit 1 - # Stoppe Dienste vor Backup # echo "Stop Pi-Ager Main service!" #${DIENSTE_START_STOP} stop @@ -339,9 +329,9 @@ fi # write buffer and clear caches sync echo 1 > /proc/sys/vm/drop_caches - +backupfullname=${BACKUP_PFAD}/${BACKUP_NAME} echo "create now Backup ${BACKUP_PFAD}/${BACKUP_NAME}.img at $(date +%T) with command dd. This needs some time to complete ..." -dd if=/dev/mmcblk0 of=${BACKUP_PFAD}/${BACKUP_NAME}.img bs=1M 2>&1 +dd if=/dev/mmcblk0 of=${backupfullname}.img bs=1M 2>&1 ddstatus=$? if [ $ddstatus -ne 0 ]; then @@ -350,22 +340,27 @@ if [ $ddstatus -ne 0 ]; then if [ $PI_AGER_MAIN_ACTIVE == 1 ]; then # set_piager_status echo "Start Pi-Ager Main service again." - systemctl start pi-ager_main & + systemctl start pi-ager_main fi - umount $NFSMOUNT + umount -l $NFSMOUNT exit 1 fi +# allow rw for all users including nobody +chmod 666 ${backupfullname}.img sync + # Starte Shrink -echo "start PiShrink $(date +%T) pishrink.sh $OPTARG ${BACKUP_PFAD}/${BACKUP_NAME}.img" +# echo "start PiShrink $(date +%T) pishrink.sh $OPTARG ${BACKUP_PFAD}/${BACKUP_NAME}.img" #read -p "Press enter to continue before pishrink call" # -d write debug file #sudo /usr/local/bin/pishrink.sh -d $OPTARG ${BACKUP_PFAD}/${BACKUP_NAME}.img -/usr/local/bin/pishrink.sh ${BACKUP_PFAD}/${BACKUP_NAME}.img +# /usr/local/bin/pishrink.sh ${BACKUP_PFAD}/${BACKUP_NAME}.img # Backup umbenennen -mv ${BACKUP_PFAD}/${BACKUP_NAME}.img ${BACKUP_PFAD}/${BACKUP_NAME}_$(date +%Y-%m-%d-%H%M%S).img +new_backup_name=${BACKUP_PFAD}/${BACKUP_NAME}_$(date +%Y-%m-%d-%H%M%S).img +echo "Final backup name is ${new_backup_name}" +mv ${BACKUP_PFAD}/${BACKUP_NAME}.img ${new_backup_name} # Backup beendet #sqlite3 /var/www/config/pi-ager.sqlite3 "BEGIN TRANSACTION;UPDATE config SET value = '0.0' where key = 'backup_status'; COMMIT;" @@ -392,28 +387,101 @@ echo -e "\n" # Prüfen, ob benoetigte Zeit kleiner als 60 sec ################## if [ $diff -lt 60 ]; then - echo -e $(date +%c)": "'Backup and shrinking successful after '$diff' seconds' + echo -e $(date +%c)": "'Backup successful after '$diff' seconds' # Wenn kleiner 3600 Sekunden, in Minuten und Sekunden umrechnen ################################################################# elif [ $diff -lt 3599 ]; then - echo -e $(date +%c)": "'Backup and shrinking successful after '$[$diff / 60] 'minute(s) '$[$diff % 60] 'seconds' + echo -e $(date +%c)": "'Backup successful after '$[$diff / 60] 'minute(s) '$[$diff % 60] 'seconds' # Wenn gleich oder groeßer 3600 Sekunden, in Stunden Minuten und Sekunden umrechnen ################################################################# elif [ $diff -ge 3600 ]; then - echo -e $(date +%c)": "'Backup and shrinking successful after '$[$diff / 3600] 'hour(s) '$[$diff % 3600 / 60] 'minutes '$[$diff % 60] 'seconds' + echo -e $(date +%c)": "'Backup successful after '$[$diff / 3600] 'hour(s) '$[$diff % 3600 / 60] 'minutes '$[$diff % 60] 'seconds' fi -# unmounten -sync -umount $NFSMOUNT +# now before shrinking this image, we have to modify this image to auto-expand during firstboot. + +echo "Modify image to auto-expand during firstboot" +echo "####################################################################################" +parted_output=$(parted -ms "$new_backup_name" unit B print | tail -n 1) +partnum=$(echo "$parted_output" | cut -d ':' -f 1) +partstart=$(echo "$parted_output" | cut -d ':' -f 2 | tr -d 'B') +loopback=$(losetup -f --show -o "$partstart" "$new_backup_name") +echo "parted_output_root = $parted_output" +echo "partnum = $partnum" +echo "partstart = $partstart" +echo "loopback = $loopback" +echo "####################################################################################" +parted_output_boot=$(parted -ms "$new_backup_name" unit B print | head -n3 | tail -n1) +partnum_boot=$(echo "$parted_output_boot" | cut -d ':' -f 1) +partstart_boot=$(echo "$parted_output_boot" | cut -d ':' -f 2 | tr -d 'B') +loopback_boot=$(losetup -f --show -o "$partstart_boot" "$new_backup_name") +echo "parted_output_boot = $parted_output_boot" +echo "partnum_boot = $partnum_boot" +echo "partstart_boot = $partstart_boot" +echo "loopback_boot = $loopback_boot" +echo "####################################################################################" + +#read -p "Press enter to continue before image mount" +mountdir=$(mktemp -d) +echo "mount directory is ${mountdir}" + +# mount boot +mount -t vfat -o shortname=winnt "$loopback_boot" "$mountdir" +if [ $? -ne 0 ]; then + echo "mount boot partion ${mountdir} failed. Exit now" + losetup -d ${loopback_boot} + losetup -d ${loopback} + umount -l $NFSMOUNT + exit 1 +fi + +###################################################### +# set auto-expand root partition on first boot +###################################################### + +cmdfile=$mountdir/cmdline.txt +sed -i '1 s/$/ quiet init=\/usr\/lib\/raspberrypi-sys-mods\/firstboot/' "$cmdfile" +echo "cmdline.txt modified, added init=/usr/lib/raspberrypi-sys-mods/firstboot" + +echo "unmount ${mountdir}" +umount ${mountdir} + +if [ $? -ne 0 ] +then + echo "Error unmounting ${mountdir}. Maybe ${mountdir} is open. Image is then corrupt." + lsof ${mountdir} + losetup -d ${loopback_boot} + losetup -d ${loopback} + umount $NFSMOUNT + exit 1 +fi + +#detach loop devices +echo "Detaching loop devices from ${new_backup_name}" +losetup -d ${loopback_boot} +losetup -d ${loopback} +rm -rf $mountdir + +echo "shrink now image, add 100MB extra space" +/usr/local/bin/image-shrink.sh "$new_backup_name" 100 + +# umount NFSMOUNT +echo "unmount $NFSMOUNT" +umount -l $NFSMOUNT +if [ $? -ne 0 ]; then + echo "umount $NFSMOUNT failed. Exit now" + exit 1 +fi # Starte pi-ager service nach Backup if [ $PI_AGER_MAIN_ACTIVE == 1 ]; then # set_piager_status - echo "Start Pi-Ager Main service again." - systemctl start pi-ager_main & + echo "Start Pi-Ager Main service again." + systemctl start pi-ager_main fi + +exit 0 diff --git a/usr/local/bin/pi-ager_image.sh b/usr/local/bin/pi-ager_image.sh index a6c504b85..2f4587a14 100644 --- a/usr/local/bin/pi-ager_image.sh +++ b/usr/local/bin/pi-ager_image.sh @@ -98,7 +98,7 @@ while getopts $VALID_COMMAND_LINE_OPTIONS options; do done if [[ "$last_backup" = true ]] && [[ "$my_image" = true ]]; then echo "Use Source_file with -f or Lastname -l for filename. Not the same!" - exit; + exit 1; fi BACKUP_STATUS=$(ps ax | grep -v grep | grep pi-ager_backup.sh) @@ -167,6 +167,9 @@ umount $NFSMOUNT # NFS-Volume mounten echo "hänge NFS-Volume $NFSVOL ein" +# avoid warning that systemd still uses old version of fstab +# systemctl daemon-reload + if [ -n "$NFSOPT" ] then echo "mount with options: $NFSOPT" @@ -208,14 +211,12 @@ if [ "$last_backup" = true ] echo "Backup path with file is" $source_file fi -if [ -z "${source_file}" ]; then - echo "$COMMAND_LINE_OPTIONS_HELP" -fi if [[ ! -f "$source_file" ]]; then echo "Source File $source_file not found!" umount $NFSMOUNT exit 1; fi + echo "Source File = $source_file" echo "do_copy = $do_copy" echo "my_image = $my_image" @@ -238,7 +239,7 @@ parted_output=$(parted -ms "$img" unit B print | tail -n 1) partnum=$(echo "$parted_output" | cut -d ':' -f 1) partstart=$(echo "$parted_output" | cut -d ':' -f 2 | tr -d 'B') loopback=$(losetup -f --show -o "$partstart" "$img") -echo "parted_output = $parted_output" +echo "parted_output_root = $parted_output" echo "partnum = $partnum" echo "partstart = $partstart" echo "loopback = $loopback" @@ -257,10 +258,31 @@ echo "########################################################################## mountdir=$(mktemp -d) echo "mount directory is ${mountdir}" +# mount root mount ${loopback} ${mountdir} #read -p "Press enter to continue after mounting $loopback to $mountdir" +# mount boot mount -t vfat -o shortname=winnt "$loopback_boot" "$mountdir/boot" + +###################################################### +# rewrite /boot/setup.txt, remove /boot/setup.log +###################################################### + +# echo "boot dir = $mountdir/boot " +# ls -al $mountdir/boot +rm $mountdir/boot/setup.txt +rm $mountdir/boot/setup.log +cd /tmp +wget -O setup.txt -nv https://raw.githubusercontent.com/Tronje-the-Falconer/Pi-Ager/entwicklung/boot/firmware/setup.txt +mv setup.txt $mountdir/boot/setup.txt +echo "setup.txt copied to $mountdir/boot/" + +# auto-expand is performed in pi-ager_backup.sh : +# cmdfile=$mountdir/boot/cmdline.txt +# sed -i '1 s/$/ quiet init=\/usr\/lib\/raspberrypi-sys-mods\/firstboot/' "$cmdfile" +# echo "cmdline.txt modified, added init=/usr/lib/raspberrypi-sys-mods/firstboot" + #read -p "Press enter to continue after mounting $loopback_boot $mountdir/boot" #echo "Copy $mountdir/boot.bak/ to $mountdir/boot/" #rsync -a --info=progress2 "$mountdir/boot.bak/" "$mountdir/boot/" @@ -314,13 +336,12 @@ chroot $chrootdir /bin/bash < /home/pi/.bash_history # rm -f /lib/modules.bak # PRUNE_MODULES=1 sudo rpi-update -systemctl enable pi-ager_main.service setup_pi-ager.service -# systemctl disable pi-ager_scale.service pi-ager_agingtable.service +systemctl disable pi-ager_main.service +echo "pi-ager_main.service disabled, will be enabled during setup_pi-ager.sh" +systemctl enable setup_pi-ager.service +echo "setup_pi-ager service enabled" #systemctl daemon-reload #systemctl reset-failed - - - - #****************************************************** # Change some settings #****************************************************** @@ -364,12 +383,13 @@ systemctl enable pi-ager_main.service setup_pi-ager.service ###################################################### # Remove System key for encrypt/decrypt ###################################################### -rm /home/pi/system_key.bin +rm -f /home/pi/system_key.bin ###################################################### # change hostname ###################################################### -raspi-config nonint do_hostname rpi-Pi-Ager +raspi-config nonint do_hostname pi-ager +echo "hostname changed to pi-ager" # rewrite /var/.htcredentials # mv /var/.htcredentials.org /var/.htcredentials @@ -378,17 +398,10 @@ raspi-config nonint do_hostname rpi-Pi-Ager # rewrite /etc/wpa_supplicant/wpa_supplicant.conf ###################################################### # mv /etc/wpa_supplicant/wpa_supplicant.conf.org /etc/wpa_supplicant/wpa_supplicant.conf +# remove all wlan connections +# rm -f /etc/NetworkManager/system-connections/* - -###################################################### -# rewrite /boot/setup.txt, remove /boot/setup.log -###################################################### -rm /boot/setup.txt -rm /boot/setup.log -wget -O setup.txt -nv https://raw.githubusercontent.com/Tronje-the-Falconer/Pi-Ager/entwicklung/boot/setup.txt -mv /setup.txt /boot/setup.txt - -###################################################### +##################################################### #Force password change for user root ###################################################### #change -d 0 root @@ -412,23 +425,28 @@ UPDATE scale2_settings SET value='300' WHERE key='measuring_interval'; UPDATE scale2_settings SET value='15' WHERE key='measuring_duration'; UPDATE scale2_settings SET value='150' WHERE key='saving_period'; UPDATE scale2_settings SET value='20' WHERE key='samples'; -UPDATE config SET value='2' WHERE key='switch_on_cooling_compressor'; -UPDATE config SET value='0' WHERE key='switch_off_cooling_compressor'; -UPDATE config SET value='25' WHERE key='switch_on_humidifier'; -UPDATE config SET value='0' WHERE key='switch_off_humidifier'; -UPDATE config SET value='5' WHERE key='delay_humidify'; +UPDATE config SET value='1.6' WHERE key='cooling_hysteresis'; +UPDATE config SET value='5' WHERE key='heating_hysteresis'; +UPDATE config SET value='3.0' WHERE key='humidifier_hysteresis'; +UPDATE config SET value='2.0' WHERE key='dehumidifier_hysteresis'; +UPDATE config SET value='-4' WHERE key='humidifier_hysteresis_offset'; +UPDATE config SET value='2' WHERE key='dehumidifier_hysteresis_offset'; +UPDATE config SET value='10' WHERE key='delay_humidify'; +UPDATE config SET value='93' WHERE key='saturation_point'; +UPDATE config SET value='40' WHERE key='temp_avg_maxlen'; +UPDATE config SET value='40' WHERE key='hum_avg_maxlen'; UPDATE config SET value='12' WHERE key='switch_on_light_hour'; UPDATE config SET value='30' WHERE key='switch_on_light_minute'; UPDATE config SET value='0' WHERE key='light_duration'; -UPDATE config SET value='21600' WHERE key='light_period'; +UPDATE config SET value='86400' WHERE key='light_period'; UPDATE config SET value='0' WHERE key='light_modus'; UPDATE config SET value='11' WHERE key='switch_on_uv_hour'; UPDATE config SET value='30' WHERE key='switch_on_uv_minute'; -UPDATE config SET value='300' WHERE key='uv_duration'; -UPDATE config SET value='21600' WHERE key='uv_period'; -UPDATE config SET value='0' WHERE key='uv_modus'; -UPDATE config SET value='3' WHERE key='modus'; -UPDATE config SET value='6' WHERE key = 'save_temperature_humidity_loops'; +UPDATE config SET value='86400' WHERE key='uv_duration'; +UPDATE config SET value='0' WHERE key='uv_period'; +UPDATE config SET value='1' WHERE key='uv_modus'; +UPDATE config SET value='4' WHERE key='modus'; +UPDATE config SET value='12' WHERE key = 'save_temperature_humidity_loops'; UPDATE config SET value='0.0' WHERE key = 'meat1_sensortype'; UPDATE config SET value='0.0' WHERE key = 'meat2_sensortype'; UPDATE config SET value='0.0' WHERE key = 'meat3_sensortype'; @@ -437,20 +455,42 @@ UPDATE config SET value='0.0' WHERE key = 'secondsensortype'; UPDATE config SET value='1.0' WHERE key = 'tft_display_type'; UPDATE config SET value='0.0' WHERE key = 'shutdown_on_batlow'; UPDATE config SET value='0.0' WHERE key = 'diagram_modus'; -UPDATE config SET value='30.0' WHERE key = 'delay_cooler'; +UPDATE config SET value='60.0' WHERE key = 'delay_cooler'; UPDATE config SET value='1' WHERE key = 'dewpoint_check'; UPDATE config SET value='0.2' WHERE key = 'humidity_check_hysteresis'; UPDATE config SET value='3600.0' WHERE key = 'customtime_for_diagrams'; -UPDATE config SET value='0.0' WHERE key = 'diagram_modus'; +UPDATE config SET value='0.0' WHERE key = 'take_off_weight_scale1'; +UPDATE config SET value='0.0' WHERE key = 'take_off_weight_scale2'; UPDATE current_values SET value='0' WHERE key = 'status_piager'; UPDATE current_values SET value='0' WHERE key = 'status_scale1'; UPDATE current_values SET value='0' WHERE key = 'status_scale2'; UPDATE current_values SET value='0' WHERE key = 'status_agingtable'; UPDATE current_values SET value='0' WHERE key = 'status_humidity_check'; - -UPDATE atc_mi_thermometer_mac SET mi_mac_last3bytes='' WHERE id='1'; -UPDATE atc_mi_thermometer_data SET mi_data='' WHERE id='1'; +UPDATE current_values SET value='0' WHERE key = 'status_light_manual'; +UPDATE current_values SET value='1' WHERE key = 'status_uv_manual'; + +UPDATE current_values SET value=NULL WHERE key = 'temperature_meat1'; +UPDATE current_values SET value=NULL WHERE key = 'temperature_meat2'; +UPDATE current_values SET value=NULL WHERE key = 'temperature_meat3'; +UPDATE current_values SET value=NULL WHERE key = 'temperature_meat4'; +UPDATE current_values SET value=NULL WHERE key = 'sensor_temperature'; +UPDATE current_values SET value=NULL WHERE key = 'sensor_humidity'; +UPDATE current_values SET value=NULL WHERE key = 'sensor_dewpoint'; +UPDATE current_values SET value=NULL WHERE key = 'sensor_extern_temperature'; +UPDATE current_values SET value=NULL WHERE key = 'sensor_extern_humidity'; +UPDATE current_values SET value=NULL WHERE key = 'sensor_extern_dewpoint'; +UPDATE current_values SET value=NULL WHERE key = 'sensor_humidity_abs'; +UPDATE current_values SET value=NULL WHERE key = 'sensor_extern_humidity_abs'; +UPDATE current_values SET value=NULL WHERE key = 'temperature_avg'; +UPDATE current_values SET value=NULL WHERE key = 'humidity_avg'; +UPDATE current_values SET value=NULL WHERE key = 'humidity_abs_avg'; + +UPDATE atc_device_name SET name='' WHERE id='1'; +UPDATE atc_data SET temperature=NULL,humidity=NULL,battvolt=NULL,battpercent=NULL,last_change=NULL WHERE id='1'; + +UPDATE time_meter SET uv_light_seconds='0',pi_ager_seconds='0' WHERE id='1'; +UPDATE config_mqtt SET broker_address=NULL,port='1883',username=NULL,password=NULL,mqtt_active='0' WHERE id='1'; DELETE FROM config_nfs_backup; delete FROM config_email_server; @@ -484,9 +524,11 @@ INSERT INTO "config_nfs_backup" ("id","nfsvol","number_of_backups","backup_name" END_SQL # Rebuild DB to reduce the size of the DB sqlite3 /var/www/config/pi-ager.sqlite3 'VACUUM;' - +sync EOF + sync + if [ "$my_image" = false ]; then chroot $chrootdir /bin/bash < /etc/hostname - sed -i "s/127.0.1.1.*$CURRENT_HOSTNAME/127.0.1.1\t$piname/g" /etc/hosts + # CURRENT_HOSTNAME=`cat /etc/hostname | tr -d " \t\n\r"` + # echo -n $piname > /etc/hostname + # sed -i "s/127.0.1.1.*$CURRENT_HOSTNAME/127.0.1.1\t$piname/g" /etc/hosts + raspi-config nonint do_hostname $piname echo "Hostname gesetzt" fi @@ -87,34 +84,96 @@ then fi # wlan Netz und Key eintragen + # remove old profiles but not PI_AGER_ap.nmconnection + # rfkill unblock wifi + mv /etc/NetworkManager/system-connections/PI_AGER_AP.nmconnection /etc/NetworkManager/system-connections/PI_AGER_AP.nmconnection.org + rm /etc/NetworkManager/system-connections/*.nmconnection + mv /etc/NetworkManager/system-connections/PI_AGER_AP.nmconnection.org /etc/NetworkManager/system-connections/PI_AGER_AP.nmconnection + # systemctl restart NetworkManager if [ -n "$wlanssid" ] #wenn nicht "" then - if [ ${#wlankey} -ge 8 ] # 8 Zeichen oder mehr + uppercase_country="${country^^}" + if [ ${#wlankey} -ge 8 ] && [ ${#uppercase_country} -eq 2 ]; # 8 Zeichen oder mehr und exakt 2 Zeichen für country then - echo "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev" > /etc/wpa_supplicant/wpa_supplicant.conf - echo "update_config=1" >> /etc/wpa_supplicant/wpa_supplicant.conf - echo "country=$country" >> /etc/wpa_supplicant/wpa_supplicant.conf - wpa_passphrase "$wlanssid" "$wlankey" >> /etc/wpa_supplicant/wpa_supplicant.conf - echo "WLAN SSID und Passphrase gesetzt" + # echo "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev" > /etc/wpa_supplicant/wpa_supplicant.conf + # echo "update_config=1" >> /etc/wpa_supplicant/wpa_supplicant.conf + # echo "country=$country" >> /etc/wpa_supplicant/wpa_supplicant.conf + # wpa_passphrase "$wlanssid" "$wlankey" >> /etc/wpa_supplicant/wpa_supplicant.conf + # echo -e "\nnetwork={\n\tssid=\x22${wlanssid}\x22\n\tpsk=\x22${wlankey}\x22\n\tkey_mgmt=WPA-PSK\n}" >> /etc/wpa_supplicant/wpa_supplicant.conf + echo "Uppercase Country = $uppercase_country" + raspi-config nonint do_wifi_country "$uppercase_country" + echo "raspi-config do_wifi_country setup finished" + # raspi-config nonint do_wifi_ssid_passphrase "$wlanssid" "$wlankey" + # nmcli device wifi connect "$wlanssid" password "$wlankey" ifname wlan0 + nmFilename='/etc/NetworkManager/system-connections/pi-ager-wlan.nmconnection' + cat < "$nmFilename" +[connection] +id=pi-ager-wlan +uuid= +type=wifi +interface-name=wlan0 +timestamp= +autoconnect=true + +[wifi] +mode=infrastructure +ssid= + +[wifi-security] +auth-alg=open +key-mgmt=wpa-psk +psk= + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +method=auto + +[proxy] +EOF + chmod -R 600 "$nmFilename" + chown -R root:root "$nmFilename" + uuid=$(uuidgen) + timestamp=$(date +%s) + modify_nmconnection "$nmFilename" "$wlanssid" "$wlankey" "$uuid" "$timestamp" + if [ $? -eq 0 ] + then + echo "WLAN SSID und Passphrase gesetzt" + else + echo "Fehler $? : WLAN SSID und Passphrase konnten nicht gesetzt werden" + fi + # restart network manager to activate + echo "restart NetworkManager" + systemctl restart NetworkManager fi fi # Configfile löschen if [ -z "$keepconf" ] #wenn "" then - rm /boot/setup.txt + rm /boot/firmware/setup.txt echo "Config gelöscht" fi # check sensor - sensorbus= - sensornum= + sensorbus=0 + sensornum=5 case $sensor in "DHT11") sensorbus=1; sensornum=1;; "DHT22") sensorbus=1; sensornum=2;; "SHT75") sensorbus=1; sensornum=3;; "SHT85") sensorbus=0; sensornum=4;; "SHT3x") sensorbus=0; sensornum=5;; + "SHT3x-mod") sensorbus=0; sensornum=6;; + "AHT1x") sensorbus=0; sensornum=7;; + "AHT1x-mod") sensorbus=0; sensornum=8;; + "AHT2x") sensorbus=0; sensornum=9;; + "AHT30") sensorbus=0; sensornum=10;; + "AHT4x-A") sensorbus=0; sensornum=11;; + "AHT4x-B") sensorbus=0; sensornum=12;; + "AHT4x-C") sensorbus=0; sensornum=13;; esac echo "Bus = $sensorbus sensor = $sensornum" @@ -127,21 +186,36 @@ then if [ $sensorbus -eq 0 ]; then # hier muss alles hin was vor dem shutdown gemacht werden soll, um auf i2c zu wechseln - rm -r /etc/modprobe.d/Pi-Ager_i2c_off.conf + rm -f /etc/modprobe.d/Pi-Ager_i2c_off.conf echo "i2c is active" elif [ $sensorbus -eq 1 ]; then # hier muss alles hin was vor dem shutdown gemacht werden soll, um auf 1wire zu wechseln cp /etc/modprobe.d/Pi-Ager_i2c_off.conf.on /etc/modprobe.d/Pi-Ager_i2c_off.conf echo "1-wire is active" - fi + fi + +# load firmware into HMI display if hmidisplay != "none" + case $hmidisplay in + "NX3224K028") echo "start firmware upload for HMI display device $hmidisplay" + nextion-fw-upload /dev/serial0 /var/www/nextion/NX3224K028/pi-ager.tft + echo "firmware upload for HMI device finished";; + "NX3224T028") echo "start firmware upload for HMI display device $hmidisplay" + nextion-fw-upload /dev/serial0 /var/www/nextion/NX3224T028/pi-ager.tft + echo "firmware upload for HMI device finished";; + "NX3224F028") echo "start firmware upload for HMI display device $hmidisplay" + nextion-fw-upload /dev/serial0 /var/www/nextion/NX3224F028/pi-ager.tft + echo "firmware upload for HMI device finished";; + esac fi +echo "disable setup_pi-ager.service now" systemctl disable setup_pi-ager.service # Setupscript in Startroutine deaktivieren, da es nur beim ersten Start benötigt wird. +# expand root file system. Not here! Is done by initramfs automatically +# raspi-config nonint do_expand_rootfs && reboot -systemctl enable pi-ager_main.service -# systemctl start pi-ager_main.service -# ifup wlan0 +# now its time to enable pi-ager_main.service to start at next boot. Reboot is initiated by rc.local after expanding file system on root partition +# start service now moved to rc.local +# systemctl enable pi-ager_main.service -# reboot -shutdown -r now +exit 0 diff --git a/var/show_wifi_connections.sh b/var/show_wifi_connections.sh new file mode 100644 index 000000000..0da71ba56 --- /dev/null +++ b/var/show_wifi_connections.sh @@ -0,0 +1,44 @@ +#!/bin/bash + ct=0; j=0 ; lp=0 + wfselect=() + + until [ $lp -eq 1 ] #wait for wifi if busy, usb wifi is slower. + do + IFS=$'\n:$\t' localwifi=($((iw dev wlan0 scan ap-force | egrep "SSID:") 2>&1)) >/dev/null 2>&1 + #if wifi device errors recheck + if (($j >= 5)); then #if busy 5 times exit to menu +# echo "WiFi Device Unavailable, cannot scan for wifi devices at this time" + break + elif echo "${localwifi[1]}" | grep "No such device (-19)" >/dev/null 2>&1; then +# echo "No Device found,trying again" + j=$((j + 1)) + sleep 2 + elif echo "${localwifi[1]}" | grep "Network is down (-100)" >/dev/null 2>&1 ; then +# echo "Network Not available, trying again" + j=$((j + 1)) + sleep 2 + elif echo "${localwifi[1]}" | grep "Read-only file system (-30)" >/dev/null 2>&1 ; then +# echo "Temporary Read only file system, trying again" + j=$((j + 1)) + sleep 2 + elif echo "${localwifi[1]}" | grep "Invalid exchange (-52)" >/dev/null 2>&1 ; then +# echo "Temporary unavailable, trying again" + j=$((j + 1)) + sleep 2 + elif echo "${localwifi[1]}" | grep -v "Device or resource busy (-16)" >/dev/null 2>&1 ; then + lp=1 + else #see if device not busy in 2 seconds +# echo "WiFi Device unavailable checking again" + j=$((j + 1)) + sleep 2 + fi + done + + #Wifi Connections found - continue + for x in "${localwifi[@]}" + do + if [ $x != "SSID" ]; then + echo "${x/ /}" + fi + done + diff --git a/var/sudowebscript.sh b/var/sudowebscript.sh index 2cd4fcd6f..f099e1b38 100644 --- a/var/sudowebscript.sh +++ b/var/sudowebscript.sh @@ -38,11 +38,11 @@ case "$1" in python3 /opt/pi-ager/piager_upload_firmware.py /dev/serial0 $2 >/dev/null 2>/dev/null & ;; reboot) # reboot - sleep 3 + sleep 4 reboot ;; shutdown) #Shutdown - sleep 3 + sleep 4 shutdown -h now ;; savewebcampicture) # macht ein Bild mit der Webcam @@ -74,14 +74,20 @@ case "$1" in sensorbusi2c) #Sensorbus wurde geaendert auf i2c # hier muss alles hin was vor dem shutdown gemacht werden soll, um auf i2c zu wechseln (SHT3x und SHT85) rm -r /etc/modprobe.d/Pi-Ager_i2c_off.conf - sleep 3 - shutdown -h now +# sleep 3 +# shutdown -h now ;; sensorbus1wire) #Sensorbus wurde geaendert auf 1wire # hier muss alles hin was vor dem shutdown gemacht werden soll, um auf 1wire zu wechseln (DHT* und SHT75) cp /etc/modprobe.d/Pi-Ager_i2c_off.conf.on /etc/modprobe.d/Pi-Ager_i2c_off.conf - sleep 3 - shutdown -h now +# sleep 3 +# shutdown -h now + ;; + set_time_date) # set system time and date when pi-ager is in hotspot mode + systemctl stop systemd-timesyncd.service + timedatectl set-time "$2" + systemctl start systemd-timesyncd.service + systemctl daemon-reload ;; *) echo "ERROR: invalid parameter: $1 (for $0)"; exit 1 #Fehlerbehandlung ;; diff --git a/var/updatessid.sh b/var/updatessid.sh new file mode 100644 index 000000000..10fae928b --- /dev/null +++ b/var/updatessid.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# call: sudo updatessid 'ssid' 'password' + #check for blank in return +# echo "$1" +# echo "" + if [ "$1" = "Cancel" ] || [ "$1" = "" ] ; then +# menu + exit + fi + + IFS="," wpassid=$(awk '/ssid="/{ print $0 }' /etc/wpa_supplicant/wpa_supplicant.conf | awk -F'ssid=' '{ print $2 }' | sed 's/\r//g'| awk 'BEGIN{ORS=","} {print}' | sed 's/\"/''/g' | sed 's/,$//') + ssids=($wpassid) + if [[ ! " ${ssids[@]} " =~ " $1 " ]]; then +# echo "Add New Wifi Network" +# echo "Selection SSID: $1" +# echo "" +# echo "Enter password for Wifi" +# read ssidpw + echo -e "\nnetwork={\n\tssid=\x22$1\x22\n\tpsk=\x22$2\x22\n\tkey_mgmt=WPA-PSK\n}" >> /etc/wpa_supplicant/wpa_supplicant.conf +# echo -e "\nnetwork={\n\tssid=\x22$1\x22\n\tpsk=\x22$2\x22\n\tkey_mgmt=WPA-PSK\n}" + else + f=0 +# echo "Change Password for Selected Wifi" + while IFS= read -r ln || [[ -n "$ln" ]] <&3; do + if [[ "$ln" == *"psk="* ]] && [ $f -eq 1 ] ;then + break + elif [[ "$ln" == *"$1"* ]] ; then + f=1 + fi + done < /etc/wpa_supplicant/wpa_supplicant.conf +# echo "Change Wifi Network Password" +# echo "Selected SSID: $1" +# echo "" +# echo "Enter password for Wifi" +# read chgpw + newpsk=$'\tpsk=\x22'$2$'\x22\n' +# echo "The entry will be" $newpsk +# echo "To be Replaced $ln" + sed -i '/'"$ln"'/c\'"$newpsk" /etc/wpa_supplicant/wpa_supplicant.conf + f=0 + fi \ No newline at end of file diff --git a/var/www/admin.php b/var/www/admin.php index d22a4ddad..a4d584d08 100644 --- a/var/www/admin.php +++ b/var/www/admin.php @@ -19,9 +19,10 @@ include 'modules/write_defrost_db.php'; // schreibt die defrost Werte in die DB include 'modules/write_nextion_type_db.php'; // nextion display type save - include 'modules/read_config_db.php'; // Liest die Grundeinstellungen Sensortyp, Hysteresen, GPIO's) - include 'modules/read_current_db.php'; - include 'modules/start_stop_uv.php'; + // include 'modules/read_config_db.php'; // Liest die Grundeinstellungen Sensortyp, Hysteresen, GPIO's) + // include 'modules/read_current_db.php'; + include 'modules/read_all_admin.php'; + include 'modules/start_stop_uv.php'; // UV-light stop/auto include 'modules/read_bus.php'; // liest den gesetzten bus-value @@ -54,6 +55,20 @@

+
@@ -61,9 +76,15 @@

- +

+ + +

+ +

+


@@ -71,23 +92,39 @@ />
/>
/>
- />
- />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />

/>
- />
- />
- />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />
+ />

-
>
+
>
@@ -107,7 +144,7 @@ function help_sensortype_noneFunction() { - +


@@ -118,12 +155,12 @@ function help_sensortype_noneFunction() { - + - + @@ -132,7 +169,11 @@ function help_sensortype_noneFunction() { - + + + + + @@ -141,7 +182,6 @@ function help_sensortype_noneFunction() { - @@ -150,12 +190,13 @@ function help_sensortype_noneFunction() { + - + @@ -164,6 +205,10 @@ function help_sensortype_noneFunction() { + + + + @@ -173,7 +218,6 @@ function help_sensortype_noneFunction() { - @@ -182,6 +226,7 @@ function help_sensortype_noneFunction() { +



1

:>>
:
: >
:>
> >
> >

2

:>>
:
: >
:>
>
> >
+ format($format) == $date; + } + + if (isset ($_POST['setdatetime'])){ + $newdatetime = $_POST['newdatetime']; + if (validateDate($newdatetime) == true) { + shell_exec('sudo /var/sudowebscript.sh set_time_date ' . '"' . $newdatetime . '"'); + echo ''; + } + else { + echo ''; + } + } + // $essid = exec("iwgetid | awk -F'\"' '{print $2}'"); + // echo 'ESSID : ' . $essid . "
"; + $ap_mode = false; + $local_ip = $_SERVER['REMOTE_ADDR']; + // echo 'local ip : ' . $local_ip . '
'; + if (strpos($local_ip, '10.0.0') !== false) { + $ap_mode = true; + // echo 'ap_mode : ' . $ap_mode . '
'; + } + // $hostname = ''; + // $addresses = exec("hostname -I"); + // echo 'hostname -I : ' . $addresses . '
'; + + // if (strpos($addresses, '10.0.0.1') !== false) { + // $ap_mode = true; + // echo 'ap_mode : ' . $ap_mode . '
'; + // } + // $address_list = explode(" ", $addresses); + // $address_list_count = count($address_list); + // if ($address_list_count == 0) { + // $hostname = ""; + // } + // else { + // $hostname = $address_list[0]; + // } + // $hostname = exec("hostname -I"); + // echo 'hostname -I : ' . $hostname . '
'; + // if ($local_ip !== '10.0.0.5') { + // if ($essid === 'RPiHotspot') { + ?> +
> +
+

+ +
+ + + + + +
+
+ + +
+
+ + +
> +
+

+ +
+ + + + +
+ +
+
+ &1'); + $ssid_count = count($ssids_with_signal); + # echo 'return status from show_wifi_connections : ' . $res . '
'; + # var_dump($ssids); + $ssids_signals = array(); + foreach ($ssids_with_signal as $ssid_with_signal) { + $ssids_signals[] = explode(':', $ssid_with_signal); + } + } + ?> +
+ + + + +
+ '; + } + else { + $si = 0; + foreach ($ssids_signals as $ssid_signal) { + if ($ssid_signal[0] != '') { + echo ''; + if ($si == 0) { + echo ''; + } + else { + echo ''; + } + echo ''; + echo ''; + } + $si++; + } + } + ?> + + + + + + + + + + +
SSIDSIGNAL
' . $ssid_signal[1] . '
  
required>
+
+ +
+
+
+
+ + + +
+ +

+ +
+
+ + + + +
+
+ +
+
+ + + '; diff --git a/var/www/calibrate_scale.php b/var/www/calibrate_scale.php index e2b935192..88010eaab 100644 --- a/var/www/calibrate_scale.php +++ b/var/www/calibrate_scale.php @@ -3,6 +3,26 @@ include 'modules/database.php'; // Schnittstelle zur Datenbank include 'modules/logging.php'; //liest die Datei fuer das logging ein + # Language festlegen + + #### BEGIN Language from DB + + $language = intval(get_table_value($config_settings_table, $language_key)); + if ($language == 1) { + $language = 'de_DE.utf8'; + } + elseif ($language == 2) { + $language = 'en_GB.utf8'; + } + setlocale(LC_ALL, $language); + + # Set the text domain as 'messages' + $domain = 'pi-ager'; + bindtextdomain($domain, "/var/www/locale"); + textdomain($domain); + + #### END Language from DB + if(isset ($_POST['scale_wizzard2'])) { $scale_number = $_POST['scale_number']; $known_weight = $_POST['scale_wizzard_weight']; @@ -45,15 +65,20 @@ // Seite aufbauen mit OK Button include 'header.php'; // Template-Kopf und Navigation echo '

' . strtoupper(_('scale wizzard'). ' - ' . _('tara scale')) . '

'; - echo '
'; + echo '
'; echo _('please relieve the load cell completely'). ' ' . _('and press ok'). '

'; echo '
'; echo ''; echo ''; echo ''; - echo ""; + echo ''; echo ""; echo '
'; + echo ''; echo '
'; echo '
'; include 'footer.php'; @@ -76,6 +101,8 @@ if (isset($_POST['scale_wizzard_cancel'])) { write_startstop_status_in_database($calibrate_scale1_key, 0); write_startstop_status_in_database($calibrate_scale2_key, 0); + $logstring = _('calibration aborted'); + logger('INFO', $logstring); header("location: settings.php"); exit(); } diff --git a/var/www/changelog.html b/var/www/changelog.html index 0a2df0b47..1787d0054 100644 --- a/var/www/changelog.html +++ b/var/www/changelog.html @@ -13,23 +13,51 @@ margin-right: 10px; } -h4 { - margin-top: 1.33em; - margin-bottom: 1.33em; -} - h3 { margin-top: 1em; margin-bottom: 1em; } -h2 { - margin-top: 0.83em; - margin-bottom: 0.83em; +h4 { + margin-top: 1.33em; + margin-bottom: 1.33em; } +

Version 4.0.0

+ +

System

+
    +
  • Pi-Ager mit Hotspot. Pi-Ager spannt ein eigenes WLAN (Hotspot oder Acesspoint) neben der Anbindung an ein lokales WLAN Netzwerk auf. Beide Netzwerke existieren parallel nebeneinander. Mit einem Tablet, Smartphone oder Notebook kann man sich mit dem Accesspoint verbinden, der Name des Netzwerks ist pi-ager und das Default-Passwort zum Verbinden ist 1234567890. Ãœblicherweise verbindet man sich in ein lokales WLAN Netz, das von einem Router aufgespannt wird und das auch mit dem Pi-Ager verbunden ist (Client mode oder Station Mode). Die Parameter für die Anmeldung an einem Router können im File setup.txt festgelegt werden und bestehen aus dem Namen des Netzwerks (SSID), dem WLAN Passwort und der Länder-Kennung (z.B. 'DE' für Deutschland). Der Pi-Ager funktioniert damit auch ohne Router und ohne Internet Verbindung. Verliert der Pi-Ager die Verbindung zum WLAN Router, kann man sich mit dem pi-ager Hotspot verbinden und mit Tablet, Smartphone oder Notebook und einem Browser über die Seite http://10.0.0.1 oder http://pi-ager in den Pi-Ager einloggen. Auf der ADMIN-Seite des Pi-Ager ist es dann möglich, die Daten für WLAN SSID und WLAN Passwort für die Verbindung zum Router einzugeben, wenn diese nicht oder nicht korrekt im File setup.txt festgelegt wurden. Auf der ADMIN-Seite kann auch das Default-Passwort für den Pi-Ager Accesspoint geändert werden. Wer via ssh und einer Terminal App z.B. Shelly mit dem Pi-Ager kommunizieren will, kann das unter der IP-Addresse 10.0.0.1 mit den User pi erreichen.
  • +
  • Reifetabellen: die Spalte 'Tage' wurde durch 'Stunden' ersetzt. Die Eingabe ist limitiert auf Werte zwischen 1 ... 240h. Vor dem Upgrade auf 4.0.0 wird empfohlen, die eigenen Reifetabellen zu exportieren und mit excel oder einem Text-Editor die Spalten-Ãœberschrift 'days' in 'hours' umzubenennen und die Werte in der Spalte 'hours' dann auf Stunden umzurechnen. Diese so modifizierten Reifetabellen können mit der Version 4.0.0 wieder importiert werden.
  • +
  • Kühler- und Heizungs-Regelung arbeitet mit getrennten und symmetrischen Hysteresen. Wenn ein externer Sensor angeschlossen ist, wird die Temperatur des externen Sensors in die Regelung einbezogen.
  • +
  • Automatisches Abtauen erst möglich, wenn die Soll-Temperatur kleiner als 8° definiert ist. Der Grenzwert kann in der DB modifiziert werden (Table 'config_defrost' -> 'temp_limit').
  • +
  • Automatisches Abtauen wahlweise mit oder ohne Umluft aktiv.
  • +
  • Pi-Ager Version mit Build Nummer wird im Footer angezeigt.
  • +
  • Im setup.txt kann ein angeschlossenes HMI TFT Display selektiert werden. Ist ein Display Modell angegeben, so wird die aktuelle Firmware für das Display automatisch geflasht. Dieser Vorgang kann bis zu ca 7 Minuten dauern und kann am Display beobachtet werden. In dieser Zeit reagiert das System nicht auf User Eingaben.
  • +
  • Auf der INFO Seite des HMI TFT Displays erscheint nun auch die IP Adresse des Pi-Ager, je nachdem, wie das WLAN im System arbeitet, entweder im Client Mode oder im Hotspot Mode. Im Hotspot-Mode wird die IP Adresse 10.0.0.1 angezeigt. Das WiFi Symbol erscheint im Client Mode weiß, im Hotspot Mode rot und wenn das WLAN inaktiv ist, erscheint das WiFi Symbol weiß mit rotem X. Das WiFi Symbol is aktiv, es kann angeklickt werden, dann erscheint auf dem Display die Info-Seite.
  • +
  • Die Pi-Ager Seiten zeigen im Header links oben an, in welcher WLAN Betriebsart sich der Pi-Ager befindet: Client Mode wird angezeigt, wenn eine Verbindung zum WLAN Router existiert. Gibt es keine Verbindung zum WLAN Router, oder ist der User mit dem Pi-Ager Hotspot verbunden, wird AP Mode angezeigt.
  • +
  • Stromüberwachung mit Stromsensor LEM-HO6P-AC: ein FIFO speichert für die zurückliegenden 3 Messzyklen den Schaltzustand des Kompressor-Relais. Durch die Auswertung dieser Daten wird die Stromüberwachung deutlich robuster.
  • +
  • Licht- und UV-Licht Steuerung: Fehler bei der Betriebsart mit Zeitpunkt und Dauer behoben, der auftrat, wenn in der definierten EIN-Zeitspanne der Zeitpunkt 0:00 Uhr enthalten ist.
  • +
  • HMI TFT Display: Der QR-Code auf der Info-Seite ist direkt mit der Pi-Ager Startseite index.php verlinkt.
  • +
  • Bluetooth MiThermometer: die Software wurde neu und Resourcen schonend kodiert.
  • +
  • Ein MQTT Client ist implementiert, der Events, alle Messwerte und den Status der Relais zur Verfügung stellt.
  • +
  • Getrennte Hysteresen für Befeuchten und Entfeuchten mit Hysterese-Offset zur Anpassung an die Berechnung des Mittelwerts der Feuchte.
  • +
  • Die ADMIN Seite ist jetzt permanent zugänglich ohne Umweg über die SETTINGS Seite.
  • +
  • Auf der MONITOR Seite werden die Mittelwerte von Temperatur, Feuchte und absolute Feuchte angezeigt, ebenso auf dem TFT Display.
  • +
  • Waagendiagramme: Startgewichte werden gestrichelt eingeblendet. Die Startgewichte werden auf der ADMIN Seite definiert.
  • +
  • Waagen: Der Gewichtsverlust über die Reifezeit wird auf der MONITOR Seite in Gramm und Prozent angezeigt.
  • +
  • Hotspot Mode: Button ergänzt für Aktualisierung der existierenden WLAN Netzwerke.
  • +
  • Hotspot Mode: captive portal eingefügt: Beim Anmelden am Pi-Ager Hotspot erscheint eine Webseite mit Informationen zum WLAN Setup auf der Pi-Ager Admin Seite.
  • +
  • Befeuchter Ãœberwachung: Wenn die Abweichung zwischen Feuchte-Sollwert und -Istwert zu groß ist, wird nach einer einstellbaren Verzögerungszeit ein Event erzeugt (humidifier failure).
  • +
  • System upgrade auf Pi OS 12 bookworm unter anderem zur Unterstützung neuer RaspberryPi Versionen. Network setup erfolgt nun mit NetworkManager.
  • +
  • ACHTUNG: WLAN Setup über /etc/wpa_supplicant/wpa_supplicant.conf wird nicht mehr unterstützt!
  • +
  • Temperatur/Feuchte-Sensoren: Unterstützung für Sensoren des Typs AHT1x, AHT2x, AHT30 und SHT4x mit I2C Interface. Da diese Sensoren andere I2C Adressen haben als die bereits unterstützten Sensoren des Typs SHT3x und SHT85, können die neuen Sensoren ohne Umbaumaßnahmen mit den bisher unterstützten Sensoren kombiniert werden.
  • +
  • SHT3x Messwertstreuung: Ein Fehler in der Software für die Messwerterfassung konnte entdeckt und korrigiert werden.
  • +
+
+

Version 3.3.3

System

@@ -279,7 +307,7 @@

Licht und UV-Licht

  • Timer werden sofort aktiv, wenn Periode oder Mode geändert werden.
  • Benachrichtigung

    -