From 0de1b04f2efc284ab144942392c727750dd2e740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Sat, 27 Apr 2024 05:49:42 +0200 Subject: [PATCH 01/13] improve config --- device_info.py | 5 +++++ grow_system_api.py | 6 +++++- moisture_sensor.py | 20 +++++++++++++++++--- sensor_data_manager.py | 6 ++++-- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/device_info.py b/device_info.py index 89c0474..83c0c1c 100644 --- a/device_info.py +++ b/device_info.py @@ -3,10 +3,15 @@ import network class DeviceInfo: + # Device Infos name = "Dev Device 1" token = "PC]-0Bmp83h7F5#U!D6KJ(A&" + server_url = 'api.growsystem.muelleronline.org' + + # Device Infos End + wlan = network.WLAN(network.STA_IF) def get_macaddress(self): diff --git a/grow_system_api.py b/grow_system_api.py index dbd4aff..51a9b1c 100644 --- a/grow_system_api.py +++ b/grow_system_api.py @@ -9,11 +9,15 @@ class GrowSystemApi: device_info = DeviceInfo() - base_url = 'api.growsystem.muellerdev.kozow.com' + base_url = '' + + def __init__(self): + self.base_url = self.device_info.server_url def say_hello(self): data = self._get_device_data() response = self.http_client.post(self.base_url + "/api/device", data) + print(response.text) jsonResult = json.loads(response.text) print(jsonResult) return jsonResult; diff --git a/moisture_sensor.py b/moisture_sensor.py index 851aaea..c37454b 100644 --- a/moisture_sensor.py +++ b/moisture_sensor.py @@ -8,9 +8,14 @@ class MoistureSensor: moisture_sensor = None most_recent_value = [] + + min_raw_value = None + max_raw_value = None - def __init__(self, moisture_sensor_data): + def __init__(self, moisture_sensor_data, min_raw_value=300, max_raw_value=65535): self.moisture_sensor_pin_int = moisture_sensor_data['pin_int'] + self.min_raw_value = min_raw_value + self.max_raw_value = max_raw_value print("Hello from moisture sensor. Sensor pin is: " + str(self.moisture_sensor_pin_int)) self.moisture_sensor = ADC(Pin(self.moisture_sensor_pin_int)) @@ -18,7 +23,16 @@ class MoistureSensor: self.most_recent_value = [ { 'type': 'moisture', - 'value': self.moisture_sensor.read_u16(), - 'unit': 'unknown' + 'value': self.convert_to_moisture_percentage(self.moisture_sensor.read_u16()), + 'unit': '%' }, ] + + def normalize_sensor_value(self, raw_value): + return (raw_value - self.min_raw_value) / (self.max_raw_value - self.min_raw_value) + + def convert_to_moisture_percentage(self, raw_value): + normalized_value = self.normalize_sensor_value(raw_value) + return round(100 - normalized_value * 100, 1) + + \ No newline at end of file diff --git a/sensor_data_manager.py b/sensor_data_manager.py index f670d93..fc64ff0 100644 --- a/sensor_data_manager.py +++ b/sensor_data_manager.py @@ -1,16 +1,18 @@ from grow_system_api import GrowSystemApi +# from device_info import DeviceInfo class SensorDataManager: - grow_system_api = None + device_info = None - base_url = 'api.growsystem.muellerdev.kozow.com' + grow_system_api = None device_id = None def __init__(self, device_id): self.grow_system_api = GrowSystemApi() + # self.device_info = DeviceInfo() self.device_id = device_id def handleData(self, data): -- 2.40.1 From 2ba5d7816e85ddf84c7f31f2c88ef237e0b4a976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Sat, 27 Apr 2024 05:49:59 +0200 Subject: [PATCH 02/13] improve config --- sensors.py | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 sensors.py diff --git a/sensors.py b/sensors.py new file mode 100644 index 0000000..db674ac --- /dev/null +++ b/sensors.py @@ -0,0 +1,3 @@ +class Sensors: + # this is a parent class for the Sensor classes + \ No newline at end of file -- 2.40.1 From a76212ab4d4e8a58daeaef9423a2c0b59403fc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Sat, 27 Apr 2024 06:27:34 +0200 Subject: [PATCH 03/13] sensors now added in loop --- device_info.py | 16 +++++++++++++++ dht22.py | 16 +++++++-------- grow_system.py | 49 +++++++++++++++++++++++++++++++++------------- moisture_sensor.py | 18 ++++++++--------- 4 files changed, 68 insertions(+), 31 deletions(-) diff --git a/device_info.py b/device_info.py index 83c0c1c..c0c9a4d 100644 --- a/device_info.py +++ b/device_info.py @@ -10,6 +10,22 @@ class DeviceInfo: server_url = 'api.growsystem.muelleronline.org' + wlan_ssid = 'Oppa-95.lan' + wlan_pw = '95%04-MM' + + sensors = [ + { + 'type': 'moisture', + 'pin_int': 26 + }, + { + 'type': 'dht22', + 'pin_int': 15 + } + ] + +# 'pump_pin_int': 24 + # Device Infos End wlan = network.WLAN(network.STA_IF) diff --git a/dht22.py b/dht22.py index 9f6a22a..05fb9f2 100644 --- a/dht22.py +++ b/dht22.py @@ -3,30 +3,30 @@ from machine import ADC, Pin class TemperatureHumiditySensor: - dht22_sensor_pin_int = -1 + sensor_pin_int = -1 - dht22_sensor = None + sensor = None most_recent_values = [] def __init__(self, settings): - print("Hello from dht22 sensor class") + print("Initialize dht22 sensor. Sensor pin is: " + str(settings['pin_int'])) print(settings) - self.dht22_sensor_pin_int = settings['pin_int'] - self.dht22_sensor = DHT22(Pin(self.dht22_sensor_pin_int, Pin.IN, Pin.PULL_UP)) + self.sensor_pin_int = settings['pin_int'] + self.sensor = DHT22(Pin(self.sensor_pin_int, Pin.IN, Pin.PULL_UP)) def read(self): try: - self.dht22_sensor.measure() + self.sensor.measure() self.most_recent_values = [ { 'type': 'temperature', - 'value': self.dht22_sensor.temperature(), + 'value': self.sensor.temperature(), 'unit': 'C' }, { 'type': 'humidity', - 'value': self.dht22_sensor.humidity(), + 'value': self.sensor.humidity(), 'unit': '%' } ] diff --git a/grow_system.py b/grow_system.py index f553d9f..6e7fd52 100644 --- a/grow_system.py +++ b/grow_system.py @@ -3,27 +3,45 @@ from moisture_sensor import MoistureSensor from dht22 import TemperatureHumiditySensor from sensor_data_manager import SensorDataManager from grow_system_api import GrowSystemApi +from device_info import DeviceInfo class GrowSystem: grow_system_api = GrowSystemApi() - moisture_sensor = None - temperature_humidity_sensor = None + # moisture_sensor = None + # temperature_humidity_sensor = None + + sensors = [] most_recent_values = [] sensor_data_manager = None device_id = None + + device_info = DeviceInfo() def __init__(self, settings): - if not self.moisture_sensor: - self.moisture_sensor = MoistureSensor(settings['moisture_sensor']) + for sensor in self.device_info.sensors: + print("Initialize sensor:") + print(sensor) + sensor_type = sensor['type'] + if sensor_type == 'moisture': + print("Found sensor of type moisture") + self.sensors.append(MoistureSensor(sensor)) + elif sensor_type == 'dht22': + print("Found sensor of type DHT22") + self.sensors.append(TemperatureHumiditySensor(sensor)) + else: + print("No sensor type configured for: " + sensor['type']) + + #if not self.moisture_sensor: + # self.moisture_sensor = MoistureSensor(settings['moisture_sensor']) - if not self.temperature_humidity_sensor: - self.temperature_humidity_sensor = TemperatureHumiditySensor(settings['temperature_humidity_sensor']) + #if not self.temperature_humidity_sensor: + # self.temperature_humidity_sensor = TemperatureHumiditySensor(settings['temperature_humidity_sensor']) def start(self): print("Say the server hello...") @@ -41,17 +59,20 @@ class GrowSystem: while True: # Reset data self.most_recent_values = [] + + for sensor in self.sensors: + sensor.read() + self.most_recent_values = self.most_recent_values + sensor.most_recent_values + print("Most recent bla") + print(sensor.most_recent_values) + # Moisture Sensor - self.moisture_sensor.read() - self.most_recent_values = self.most_recent_values + self.moisture_sensor.most_recent_value + # self.moisture_sensor.read() + # self.most_recent_values = self.most_recent_values + self.moisture_sensor.most_recent_value # Temperature and Humidity Sensor - self.temperature_humidity_sensor.read() - self.most_recent_values = self.most_recent_values + self.temperature_humidity_sensor.most_recent_values - - print("Most recent bla") - print(self.most_recent_values) - + # self.temperature_humidity_sensor.read() + # self.most_recent_values = self.most_recent_values + self.temperature_humidity_sensor.most_recent_values self.sensor_data_manager.handleData(self.most_recent_values) time.sleep(5) diff --git a/moisture_sensor.py b/moisture_sensor.py index c37454b..08f72b7 100644 --- a/moisture_sensor.py +++ b/moisture_sensor.py @@ -3,27 +3,27 @@ from machine import ADC, Pin class MoistureSensor: - moisture_sensor_pin_int = -1 + sensor_pin_int = -1 - moisture_sensor = None + sensor = None - most_recent_value = [] + most_recent_values = [] min_raw_value = None max_raw_value = None - def __init__(self, moisture_sensor_data, min_raw_value=300, max_raw_value=65535): - self.moisture_sensor_pin_int = moisture_sensor_data['pin_int'] + def __init__(self, sensor_data, min_raw_value=300, max_raw_value=65535): + print("Initialize moisture sensor. Sensor pin is: " + str(sensor_data['pin_int'])) + self.sensor_pin_int = sensor_data['pin_int'] self.min_raw_value = min_raw_value self.max_raw_value = max_raw_value - print("Hello from moisture sensor. Sensor pin is: " + str(self.moisture_sensor_pin_int)) - self.moisture_sensor = ADC(Pin(self.moisture_sensor_pin_int)) + self.sensor = ADC(Pin(self.sensor_pin_int)) def read(self): - self.most_recent_value = [ + self.most_recent_values = [ { 'type': 'moisture', - 'value': self.convert_to_moisture_percentage(self.moisture_sensor.read_u16()), + 'value': self.convert_to_moisture_percentage(self.sensor.read_u16()), 'unit': '%' }, ] -- 2.40.1 From b36b1b3c90e6ea357176e65d85ebe8ed61b9f6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Sat, 27 Apr 2024 07:30:12 +0200 Subject: [PATCH 04/13] sensors now added in loop --- device_info.py | 5 ++--- dht22.py | 5 +++-- grow_system.py | 15 +++++---------- grow_system_api.py | 6 ++---- main.py | 2 -- moisture_sensor.py | 19 ++++++++++--------- sensor_data_manager.py | 3 +-- sensors.py | 7 +++++++ 8 files changed, 30 insertions(+), 32 deletions(-) diff --git a/device_info.py b/device_info.py index c0c9a4d..77ea2d1 100644 --- a/device_info.py +++ b/device_info.py @@ -23,9 +23,8 @@ class DeviceInfo: 'pin_int': 15 } ] - -# 'pump_pin_int': 24 - + + read_secs = 60 # Device Infos End wlan = network.WLAN(network.STA_IF) diff --git a/dht22.py b/dht22.py index 05fb9f2..c022666 100644 --- a/dht22.py +++ b/dht22.py @@ -1,15 +1,16 @@ +from sensors import Sensors from dht import DHT22 from machine import ADC, Pin -class TemperatureHumiditySensor: - sensor_pin_int = -1 +class TemperatureHumiditySensor(Sensors): sensor = None most_recent_values = [] def __init__(self, settings): + super().__init__(settings) print("Initialize dht22 sensor. Sensor pin is: " + str(settings['pin_int'])) print(settings) self.sensor_pin_int = settings['pin_int'] diff --git a/grow_system.py b/grow_system.py index 6e7fd52..aeaf915 100644 --- a/grow_system.py +++ b/grow_system.py @@ -25,6 +25,7 @@ class GrowSystem: def __init__(self, settings): for sensor in self.device_info.sensors: + print("") print("Initialize sensor:") print(sensor) sensor_type = sensor['type'] @@ -61,19 +62,13 @@ class GrowSystem: self.most_recent_values = [] for sensor in self.sensors: + print("Read sensor of type " + sensor.type + " at pin " + str(sensor.sensor_pin_int)) sensor.read() + for measurement in sensor.most_recent_values: + print(f"Got {measurement['value']} {measurement['unit']} ({measurement['type']})") self.most_recent_values = self.most_recent_values + sensor.most_recent_values - print("Most recent bla") - print(sensor.most_recent_values) - - # Moisture Sensor - # self.moisture_sensor.read() - # self.most_recent_values = self.most_recent_values + self.moisture_sensor.most_recent_value - # Temperature and Humidity Sensor - # self.temperature_humidity_sensor.read() - # self.most_recent_values = self.most_recent_values + self.temperature_humidity_sensor.most_recent_values self.sensor_data_manager.handleData(self.most_recent_values) - time.sleep(5) + time.sleep(self.device_info.read_secs) diff --git a/grow_system_api.py b/grow_system_api.py index 51a9b1c..0e3376c 100644 --- a/grow_system_api.py +++ b/grow_system_api.py @@ -15,16 +15,14 @@ class GrowSystemApi: self.base_url = self.device_info.server_url def say_hello(self): - data = self._get_device_data() - response = self.http_client.post(self.base_url + "/api/device", data) + response = self.http_client.post(self.base_url + "/api/device", self._get_device_data()) print(response.text) - jsonResult = json.loads(response.text) + jsonResult = json.loads(response.text) print(jsonResult) return jsonResult; def send_measurements(self, device_id, data): url = self.base_url + "/api/device/" + str(device_id) + "/sensor-log" - print(url) response = self.http_client.post(url, data) return json.loads(response.text) diff --git a/main.py b/main.py index 3f6e225..241af6c 100644 --- a/main.py +++ b/main.py @@ -44,13 +44,11 @@ if __name__ == '__main__': print("Connect WLAN") wlanClient = WlanClient(settings['wlan_ssid'], settings['wlan_pw']) wlanClient.connect() - print("---------------------------------------") print("") di = DeviceInfo() print("Device Infos:") print(di.get_all_device_infos()) - print("---------------------------------------") print("") print("Start grow system") diff --git a/moisture_sensor.py b/moisture_sensor.py index 08f72b7..e11ca76 100644 --- a/moisture_sensor.py +++ b/moisture_sensor.py @@ -1,10 +1,10 @@ # Moisture Sensor Class +from sensors import Sensors from machine import ADC, Pin -class MoistureSensor: - sensor_pin_int = -1 - +class MoistureSensor(Sensors): + sensor = None most_recent_values = [] @@ -13,6 +13,7 @@ class MoistureSensor: max_raw_value = None def __init__(self, sensor_data, min_raw_value=300, max_raw_value=65535): + super().__init__(sensor_data) print("Initialize moisture sensor. Sensor pin is: " + str(sensor_data['pin_int'])) self.sensor_pin_int = sensor_data['pin_int'] self.min_raw_value = min_raw_value @@ -21,12 +22,12 @@ class MoistureSensor: def read(self): self.most_recent_values = [ - { - 'type': 'moisture', - 'value': self.convert_to_moisture_percentage(self.sensor.read_u16()), - 'unit': '%' - }, - ] + { + 'type': 'moisture', + 'value': self.convert_to_moisture_percentage(self.sensor.read_u16()), + 'unit': '%' + }, + ] def normalize_sensor_value(self, raw_value): return (raw_value - self.min_raw_value) / (self.max_raw_value - self.min_raw_value) diff --git a/sensor_data_manager.py b/sensor_data_manager.py index fc64ff0..87dbf39 100644 --- a/sensor_data_manager.py +++ b/sensor_data_manager.py @@ -17,5 +17,4 @@ class SensorDataManager: def handleData(self, data): jsonResponse = self.grow_system_api.send_measurements(self.device_id, data) - print("---- Response: -----") - print(jsonResponse) \ No newline at end of file + print("Response message: " + jsonResponse['message']) \ No newline at end of file diff --git a/sensors.py b/sensors.py index db674ac..04beaaa 100644 --- a/sensors.py +++ b/sensors.py @@ -1,3 +1,10 @@ class Sensors: # this is a parent class for the Sensor classes + sensor_pin_int = -1 + + type = "unset" + + def __init__(self, settings): + self.type = settings['type'] + \ No newline at end of file -- 2.40.1 From e59712a7f9b0a425146e7bbcf50834b88441c7e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Sat, 27 Apr 2024 23:36:55 +0200 Subject: [PATCH 05/13] add ambilight sensor class --- device_info.py | 18 +++++++++++++----- grow_system.py | 4 ++++ sensors.py | 3 +++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/device_info.py b/device_info.py index 77ea2d1..65ab51a 100644 --- a/device_info.py +++ b/device_info.py @@ -17,14 +17,22 @@ class DeviceInfo: { 'type': 'moisture', 'pin_int': 26 - }, + }, { - 'type': 'dht22', - 'pin_int': 15 - } + 'type': 'ambilight', + 'pin_int': 8, # for compatibility only + 'pin_int_sda': 8, + 'pin_int_scl': 9 + }, + + + # { + # 'type': 'dht22', + # 'pin_int': 15 + # } ] - read_secs = 60 + read_secs = 5 # Device Infos End wlan = network.WLAN(network.STA_IF) diff --git a/grow_system.py b/grow_system.py index aeaf915..3528ea9 100644 --- a/grow_system.py +++ b/grow_system.py @@ -1,6 +1,7 @@ import time from moisture_sensor import MoistureSensor from dht22 import TemperatureHumiditySensor +from ambilight_sensor import AmbilightSensor from sensor_data_manager import SensorDataManager from grow_system_api import GrowSystemApi from device_info import DeviceInfo @@ -35,6 +36,9 @@ class GrowSystem: elif sensor_type == 'dht22': print("Found sensor of type DHT22") self.sensors.append(TemperatureHumiditySensor(sensor)) + elif sensor_type == 'ambilight': + print("Found sensor of type GY302/BH1750") + self.sensors.append(AmbilightSensor(sensor)) else: print("No sensor type configured for: " + sensor['type']) diff --git a/sensors.py b/sensors.py index 04beaaa..23ad803 100644 --- a/sensors.py +++ b/sensors.py @@ -2,9 +2,12 @@ class Sensors: # this is a parent class for the Sensor classes sensor_pin_int = -1 + sensor = None + type = "unset" def __init__(self, settings): self.type = settings['type'] + print("Initialize " + self.type + " sensor. Sensor pin is: " + str(settings['pin_int'])) \ No newline at end of file -- 2.40.1 From 3942ac787e4f01e4dcd8462a21ddd13483845f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Sat, 27 Apr 2024 23:37:01 +0200 Subject: [PATCH 06/13] add ambilight sensor class --- ambilight_sensor.py | 34 +++++++++++ bh1750.old_1/__init__.py | 1 + bh1750.old_1/bh1750.py | 118 +++++++++++++++++++++++++++++++++++++++ lib/bh1750.py | 62 ++++++++++++++++++++ 4 files changed, 215 insertions(+) create mode 100644 ambilight_sensor.py create mode 100644 bh1750.old_1/__init__.py create mode 100644 bh1750.old_1/bh1750.py create mode 100644 lib/bh1750.py diff --git a/ambilight_sensor.py b/ambilight_sensor.py new file mode 100644 index 0000000..c8f0a3c --- /dev/null +++ b/ambilight_sensor.py @@ -0,0 +1,34 @@ +from sensors import Sensors +from machine import Pin, I2C +from utime import sleep +from lib.bh1750 import BH1750 + + +class AmbilightSensor(Sensors): + + + most_recent_values = [] + + def __init__(self, settings): + super().__init__(settings) + print(settings) # TODO remove + self.sensor_pin_int = settings['pin_int'] + # self.sensor = DHT22(Pin(self.sensor_pin_int, Pin.IN, Pin.PULL_UP)) + self.sensor = BH1750(I2C(0, sda=Pin(settings['pin_int_sda']), scl=Pin(settings['pin_int_scl']))) + + def read(self): + try: + measurement = self.sensor.luminance(BH1750.ONCE_HIRES_1) + print("ambilight ..") + print(measurement) + self.most_recent_values = [ + { + 'type': 'ambilight', + 'value': measurement, + 'unit': '-' + }, + ] + except OSError: + print('Ambilight Error reading temperature/humidity. Check wires') + print() + diff --git a/bh1750.old_1/__init__.py b/bh1750.old_1/__init__.py new file mode 100644 index 0000000..ab5e217 --- /dev/null +++ b/bh1750.old_1/__init__.py @@ -0,0 +1 @@ +from .bh1750 import BH1750 diff --git a/bh1750.old_1/bh1750.py b/bh1750.old_1/bh1750.py new file mode 100644 index 0000000..21cebbe --- /dev/null +++ b/bh1750.old_1/bh1750.py @@ -0,0 +1,118 @@ +# https://github.com/flrrth/pico-bh1750 + +import math + +from micropython import const +from utime import sleep_ms + + +class BH1750: + """Class for the BH1750 digital Ambient Light Sensor + + The datasheet can be found at https://components101.com/sites/default/files/component_datasheet/BH1750.pdf + """ + + MEASUREMENT_MODE_CONTINUOUSLY = const(1) + MEASUREMENT_MODE_ONE_TIME = const(2) + + RESOLUTION_HIGH = const(0) + RESOLUTION_HIGH_2 = const(1) + RESOLUTION_LOW = const(2) + + MEASUREMENT_TIME_DEFAULT = const(69) + MEASUREMENT_TIME_MIN = const(31) + MEASUREMENT_TIME_MAX = const(254) + + def __init__(self, address, i2c): + self._address = address + self._i2c = i2c + self._measurement_mode = BH1750.MEASUREMENT_MODE_ONE_TIME + self._resolution = BH1750.RESOLUTION_HIGH + self._measurement_time = BH1750.MEASUREMENT_TIME_DEFAULT + + self._write_measurement_time() + self._write_measurement_mode() + + def configure(self, measurement_mode: int, resolution: int, measurement_time: int): + """Configures the BH1750. + + Keyword arguments: + measurement_mode -- measure either continuously or once + resolution -- return measurements in either high, high2 or low resolution + measurement_time -- the duration of a single measurement + """ + if measurement_time not in range(BH1750.MEASUREMENT_TIME_MIN, BH1750.MEASUREMENT_TIME_MAX + 1): + raise ValueError("measurement_time must be between {0} and {1}" + .format(BH1750.MEASUREMENT_TIME_MIN, BH1750.MEASUREMENT_TIME_MAX)) + + self._measurement_mode = measurement_mode + self._resolution = resolution + self._measurement_time = measurement_time + + self._write_measurement_time() + self._write_measurement_mode() + + def _write_measurement_time(self): + buffer = bytearray(1) + + high_bit = 1 << 6 | self._measurement_time >> 5 + low_bit = 3 << 5 | (self._measurement_time << 3) >> 3 + + buffer[0] = high_bit + self._i2c.writeto(self._address, buffer) + + buffer[0] = low_bit + self._i2c.writeto(self._address, buffer) + + def _write_measurement_mode(self): + buffer = bytearray(1) + + buffer[0] = self._measurement_mode << 4 | self._resolution + self._i2c.writeto(self._address, buffer) + sleep_ms(24 if self._measurement_time == BH1750.RESOLUTION_LOW else 180) + + def reset(self): + """Clear the illuminance data register.""" + self._i2c.writeto(self._address, bytearray(b'\x07')) + + def power_on(self): + """Powers on the BH1750.""" + self._i2c.writeto(self._address, bytearray(b'\x01')) + + def power_off(self): + """Powers off the BH1750.""" + self._i2c.writeto(self._address, bytearray(b'\x00')) + + @property + def measurement(self) -> float: + """Returns the latest measurement.""" + if self._measurement_mode == BH1750.MEASUREMENT_MODE_ONE_TIME: + self._write_measurement_mode() + + buffer = bytearray(2) + self._i2c.readfrom_into(self._address, buffer) + lux = (buffer[0] << 8 | buffer[1]) / (1.2 * (BH1750.MEASUREMENT_TIME_DEFAULT / self._measurement_time)) + + if self._resolution == BH1750.RESOLUTION_HIGH_2: + return lux / 2 + else: + return lux + + def measurements(self) -> float: + """This is a generator function that continues to provide the latest measurement. Because the measurement time + is greatly affected by resolution and the configured measurement time, this function attemts to calculate the + appropriate sleep time between measurements. + + Example usage: + + for measurement in bh1750.measurements(): # bh1750 is an instance of this class + print(measurement) + """ + while True: + yield self.measurement + + if self._measurement_mode == BH1750.MEASUREMENT_MODE_CONTINUOUSLY: + base_measurement_time = 16 if self._measurement_time == BH1750.RESOLUTION_LOW else 120 + sleep_ms(math.ceil(base_measurement_time * self._measurement_time / BH1750.MEASUREMENT_TIME_DEFAULT)) + + diff --git a/lib/bh1750.py b/lib/bh1750.py new file mode 100644 index 0000000..0f91b49 --- /dev/null +++ b/lib/bh1750.py @@ -0,0 +1,62 @@ +""" +Micropython BH1750 ambient light sensor driver. +* https://github.com/PinkInk/upylib/tree/master/bh1750 +""" + +from utime import sleep_ms + + +class BH1750(): + """Micropython BH1750 ambient light sensor driver.""" + + PWR_OFF = 0x00 + PWR_ON = 0x01 + RESET = 0x07 + + # modes + CONT_LOWRES = 0x13 + CONT_HIRES_1 = 0x10 + CONT_HIRES_2 = 0x11 + ONCE_HIRES_1 = 0x20 + ONCE_HIRES_2 = 0x21 + ONCE_LOWRES = 0x23 + + # default addr=0x23 if addr pin floating or pulled to ground + # addr=0x5c if addr pin pulled high + def __init__(self, bus, addr=0x23): + self.bus = bus + self.addr = addr + self.off() + self.reset() + + def off(self): + """Turn sensor off.""" + self.set_mode(self.PWR_OFF) + + def on(self): + """Turn sensor on.""" + self.set_mode(self.PWR_ON) + + def reset(self): + """Reset sensor, turn on first if required.""" + self.on() + self.set_mode(self.RESET) + + def set_mode(self, mode): + """Set sensor mode.""" + self.mode = mode + self.bus.writeto(self.addr, bytes([self.mode])) + + def luminance(self, mode): + """Sample luminance (in lux), using specified sensor mode.""" + # continuous modes + if mode & 0x10 and mode != self.mode: + self.set_mode(mode) + # one shot modes + if mode & 0x20: + self.set_mode(mode) + # earlier measurements return previous reading + sleep_ms(24 if mode in (0x13, 0x23) else 180) + data = self.bus.readfrom(self.addr, 2) + factor = 2.0 if mode in (0x11, 0x21) else 1.0 + return (data[0]<<8 | data[1]) / (1.2 * factor) \ No newline at end of file -- 2.40.1 From 389996f0b353f45c445a4831366055ed143669dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Sat, 4 May 2024 11:46:32 +0200 Subject: [PATCH 07/13] Save --- grow_system_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grow_system_api.py b/grow_system_api.py index 0e3376c..5b9ccb3 100644 --- a/grow_system_api.py +++ b/grow_system_api.py @@ -15,7 +15,7 @@ class GrowSystemApi: self.base_url = self.device_info.server_url def say_hello(self): - response = self.http_client.post(self.base_url + "/api/device", self._get_device_data()) + response = self.http_client.post(self.base_url + "/api/device/hello", self._get_device_data()) print(response.text) jsonResult = json.loads(response.text) print(jsonResult) -- 2.40.1 From f8a7f47fbfb5a520a974238129920751215ed267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Sat, 4 May 2024 15:32:26 +0200 Subject: [PATCH 08/13] add pico stand --- dev_pi_pico_2405041205/ambilight_sensor.py | 34 +++++++ dev_pi_pico_2405041205/bh1750.py | 62 ++++++++++++ dev_pi_pico_2405041205/device_info.py | 69 +++++++++++++ dev_pi_pico_2405041205/dht22.py | 36 +++++++ dev_pi_pico_2405041205/engine.py | 23 +++++ dev_pi_pico_2405041205/grow_system.py | 96 +++++++++++++++++++ dev_pi_pico_2405041205/grow_system_api.py | 31 ++++++ dev_pi_pico_2405041205/http_client.py | 35 +++++++ dev_pi_pico_2405041205/main.py | 57 +++++++++++ dev_pi_pico_2405041205/moisture_sensor.py | 39 ++++++++ dev_pi_pico_2405041205/pump.py | 7 ++ dev_pi_pico_2405041205/sensor_data_manager.py | 20 ++++ dev_pi_pico_2405041205/sensors.py | 13 +++ dev_pi_pico_2405041205/wlan.py | 39 ++++++++ main.py | 30 +++--- 15 files changed, 579 insertions(+), 12 deletions(-) create mode 100644 dev_pi_pico_2405041205/ambilight_sensor.py create mode 100644 dev_pi_pico_2405041205/bh1750.py create mode 100644 dev_pi_pico_2405041205/device_info.py create mode 100644 dev_pi_pico_2405041205/dht22.py create mode 100644 dev_pi_pico_2405041205/engine.py create mode 100644 dev_pi_pico_2405041205/grow_system.py create mode 100644 dev_pi_pico_2405041205/grow_system_api.py create mode 100644 dev_pi_pico_2405041205/http_client.py create mode 100644 dev_pi_pico_2405041205/main.py create mode 100644 dev_pi_pico_2405041205/moisture_sensor.py create mode 100644 dev_pi_pico_2405041205/pump.py create mode 100644 dev_pi_pico_2405041205/sensor_data_manager.py create mode 100644 dev_pi_pico_2405041205/sensors.py create mode 100644 dev_pi_pico_2405041205/wlan.py diff --git a/dev_pi_pico_2405041205/ambilight_sensor.py b/dev_pi_pico_2405041205/ambilight_sensor.py new file mode 100644 index 0000000..c8f0a3c --- /dev/null +++ b/dev_pi_pico_2405041205/ambilight_sensor.py @@ -0,0 +1,34 @@ +from sensors import Sensors +from machine import Pin, I2C +from utime import sleep +from lib.bh1750 import BH1750 + + +class AmbilightSensor(Sensors): + + + most_recent_values = [] + + def __init__(self, settings): + super().__init__(settings) + print(settings) # TODO remove + self.sensor_pin_int = settings['pin_int'] + # self.sensor = DHT22(Pin(self.sensor_pin_int, Pin.IN, Pin.PULL_UP)) + self.sensor = BH1750(I2C(0, sda=Pin(settings['pin_int_sda']), scl=Pin(settings['pin_int_scl']))) + + def read(self): + try: + measurement = self.sensor.luminance(BH1750.ONCE_HIRES_1) + print("ambilight ..") + print(measurement) + self.most_recent_values = [ + { + 'type': 'ambilight', + 'value': measurement, + 'unit': '-' + }, + ] + except OSError: + print('Ambilight Error reading temperature/humidity. Check wires') + print() + diff --git a/dev_pi_pico_2405041205/bh1750.py b/dev_pi_pico_2405041205/bh1750.py new file mode 100644 index 0000000..0f91b49 --- /dev/null +++ b/dev_pi_pico_2405041205/bh1750.py @@ -0,0 +1,62 @@ +""" +Micropython BH1750 ambient light sensor driver. +* https://github.com/PinkInk/upylib/tree/master/bh1750 +""" + +from utime import sleep_ms + + +class BH1750(): + """Micropython BH1750 ambient light sensor driver.""" + + PWR_OFF = 0x00 + PWR_ON = 0x01 + RESET = 0x07 + + # modes + CONT_LOWRES = 0x13 + CONT_HIRES_1 = 0x10 + CONT_HIRES_2 = 0x11 + ONCE_HIRES_1 = 0x20 + ONCE_HIRES_2 = 0x21 + ONCE_LOWRES = 0x23 + + # default addr=0x23 if addr pin floating or pulled to ground + # addr=0x5c if addr pin pulled high + def __init__(self, bus, addr=0x23): + self.bus = bus + self.addr = addr + self.off() + self.reset() + + def off(self): + """Turn sensor off.""" + self.set_mode(self.PWR_OFF) + + def on(self): + """Turn sensor on.""" + self.set_mode(self.PWR_ON) + + def reset(self): + """Reset sensor, turn on first if required.""" + self.on() + self.set_mode(self.RESET) + + def set_mode(self, mode): + """Set sensor mode.""" + self.mode = mode + self.bus.writeto(self.addr, bytes([self.mode])) + + def luminance(self, mode): + """Sample luminance (in lux), using specified sensor mode.""" + # continuous modes + if mode & 0x10 and mode != self.mode: + self.set_mode(mode) + # one shot modes + if mode & 0x20: + self.set_mode(mode) + # earlier measurements return previous reading + sleep_ms(24 if mode in (0x13, 0x23) else 180) + data = self.bus.readfrom(self.addr, 2) + factor = 2.0 if mode in (0x11, 0x21) else 1.0 + return (data[0]<<8 | data[1]) / (1.2 * factor) \ No newline at end of file diff --git a/dev_pi_pico_2405041205/device_info.py b/dev_pi_pico_2405041205/device_info.py new file mode 100644 index 0000000..a61681e --- /dev/null +++ b/dev_pi_pico_2405041205/device_info.py @@ -0,0 +1,69 @@ +import network + + +class DeviceInfo: + + # Device Infos + name = "Dev Device 1" + + token = "PC]-0Bmp83h7F5#U!D6KJ(A&" + + server_url = 'api.growsystem.muelleronline.org' + + wlan_ssid = 'Oppa-95.lan' + wlan_pw = '95%04-MM' + + sensors = [ + { + 'type': 'moisture', + 'pin_int': 26 + }, + { + 'type': 'ambilight', + 'pin_int': 8, # for compatibility only + 'pin_int_sda': 8, + 'pin_int_scl': 9 + }, + + + # { + # 'type': 'dht22', + # 'pin_int': 15 + # } + ] + + engines = [ + { + 'type': 'pump', + 'pins': [15] + } + ] + + read_secs = 5 + # Device Infos End + + wlan = network.WLAN(network.STA_IF) + + def get_macaddress(self): + return self._format_mac(self.wlan.config('mac').hex()) + + def get_ipaddress(self): + return self.wlan.ifconfig()[0] + + def get_all_device_infos(self): + return { + 'name': self.name, + 'mac_address': self.get_macaddress(), + 'ip_address': self.get_ipaddress(), + 'token': self.token} + + def _format_mac(self, mac): + # Split the MAC address into pairs of two characters each + pairs = [mac[i:i+2] for i in range(0, len(mac), 2)] + # Join the pairs with colons to create the formatted MAC address + formatted_mac = ":".join(pairs) + return formatted_mac + + + + \ No newline at end of file diff --git a/dev_pi_pico_2405041205/dht22.py b/dev_pi_pico_2405041205/dht22.py new file mode 100644 index 0000000..c022666 --- /dev/null +++ b/dev_pi_pico_2405041205/dht22.py @@ -0,0 +1,36 @@ +from sensors import Sensors +from dht import DHT22 +from machine import ADC, Pin + + +class TemperatureHumiditySensor(Sensors): + + sensor = None + + most_recent_values = [] + + def __init__(self, settings): + super().__init__(settings) + print("Initialize dht22 sensor. Sensor pin is: " + str(settings['pin_int'])) + print(settings) + self.sensor_pin_int = settings['pin_int'] + self.sensor = DHT22(Pin(self.sensor_pin_int, Pin.IN, Pin.PULL_UP)) + + def read(self): + try: + self.sensor.measure() + self.most_recent_values = [ + { + 'type': 'temperature', + 'value': self.sensor.temperature(), + 'unit': 'C' + }, + { + 'type': 'humidity', + 'value': self.sensor.humidity(), + 'unit': '%' + } + ] + except OSError: + print('DHT22 Error reading temperature/humidity. Check wires') + print() diff --git a/dev_pi_pico_2405041205/engine.py b/dev_pi_pico_2405041205/engine.py new file mode 100644 index 0000000..38bf29c --- /dev/null +++ b/dev_pi_pico_2405041205/engine.py @@ -0,0 +1,23 @@ +from machine import Pin + + +class Engine(): + + pins = [] + + engine = None + + def __init__(self, engine): + print("Hello from Engine parent class") + print(engine) + self.pins = engine['pins'] + self.engine = Pin(self.pins[0], Pin.OUT) + + def on(self): + print("engine on") + self.engine.value(1) + + def off(self): + print("engine off") + self.engine.value(0) + diff --git a/dev_pi_pico_2405041205/grow_system.py b/dev_pi_pico_2405041205/grow_system.py new file mode 100644 index 0000000..3861c5a --- /dev/null +++ b/dev_pi_pico_2405041205/grow_system.py @@ -0,0 +1,96 @@ +import time +from moisture_sensor import MoistureSensor +from dht22 import TemperatureHumiditySensor +from ambilight_sensor import AmbilightSensor +from pump import Pump +from sensor_data_manager import SensorDataManager +from grow_system_api import GrowSystemApi +from device_info import DeviceInfo + + +class GrowSystem: + + grow_system_api = GrowSystemApi() + + # moisture_sensor = None + # temperature_humidity_sensor = None + + sensors = [] + + engines = [] + + most_recent_values = [] + + sensor_data_manager = None + + device_id = None + + device_info = DeviceInfo() + + def __init__(self, settings): + # Init sensors + for sensor in self.device_info.sensors: + print("") + print("Initialize sensor:") + print(sensor) + sensor_type = sensor['type'] + if sensor_type == 'moisture': + print("Found sensor of type moisture") + self.sensors.append(MoistureSensor(sensor)) + elif sensor_type == 'dht22': + print("Found sensor of type DHT22") + self.sensors.append(TemperatureHumiditySensor(sensor)) + elif sensor_type == 'ambilight': + print("Found sensor of type GY302/BH1750") + self.sensors.append(AmbilightSensor(sensor)) + else: + print("No sensor type configured for: " + sensor['type']) + + # Init engines + for engine in self.device_info.engines: + print("") + print("Initialize engine:") + print(engine) + engine_type = engine['type'] + if engine_type == 'pump': + print("Found egine of type pump") + self.engines.append(Pump(engine)) + self.engines[0].on() + time.sleep(15) + self.engines[0].off() + + + #if not self.moisture_sensor: + # self.moisture_sensor = MoistureSensor(settings['moisture_sensor']) + + #if not self.temperature_humidity_sensor: + # self.temperature_humidity_sensor = TemperatureHumiditySensor(settings['temperature_humidity_sensor']) + + def start(self): + print("Say the server hello...") + result = self.grow_system_api.say_hello() + message = result['message'] + + if message != 'OK': + print("Device not activated. Stopping") + return + + self.device_id = result['data']['device_id'] + self.sensor_data_manager = SensorDataManager(self.device_id) + + print("Start reading sensors ...") + while True: + # Reset data + self.most_recent_values = [] + + for sensor in self.sensors: + print("Read sensor of type " + sensor.type + " at pin " + str(sensor.sensor_pin_int)) + sensor.read() + for measurement in sensor.most_recent_values: + print(f"Got {measurement['value']} {measurement['unit']} ({measurement['type']})") + self.most_recent_values = self.most_recent_values + sensor.most_recent_values + + self.sensor_data_manager.handleData(self.most_recent_values) + + time.sleep(self.device_info.read_secs) + diff --git a/dev_pi_pico_2405041205/grow_system_api.py b/dev_pi_pico_2405041205/grow_system_api.py new file mode 100644 index 0000000..0e3376c --- /dev/null +++ b/dev_pi_pico_2405041205/grow_system_api.py @@ -0,0 +1,31 @@ +from http_client import HTTPClient +from device_info import DeviceInfo +import json + + +class GrowSystemApi: + + http_client = HTTPClient() + + device_info = DeviceInfo() + + base_url = '' + + def __init__(self): + self.base_url = self.device_info.server_url + + def say_hello(self): + response = self.http_client.post(self.base_url + "/api/device", self._get_device_data()) + print(response.text) + jsonResult = json.loads(response.text) + print(jsonResult) + return jsonResult; + + def send_measurements(self, device_id, data): + url = self.base_url + "/api/device/" + str(device_id) + "/sensor-log" + response = self.http_client.post(url, data) + return json.loads(response.text) + + def _get_device_data(self): + return self.device_info.get_all_device_infos() + diff --git a/dev_pi_pico_2405041205/http_client.py b/dev_pi_pico_2405041205/http_client.py new file mode 100644 index 0000000..fd197ed --- /dev/null +++ b/dev_pi_pico_2405041205/http_client.py @@ -0,0 +1,35 @@ +import urequests +import json + +class HTTPClient: + def __init__(self): + pass + + def get(self, url): + url = 'https://' + url + try: + # headers = {'Content-Type': 'application/json'} + response = urequests.get(url) + if response.status_code == 200: + print("Data sent, got response") + return response + else: + print("Failed to get data. Status code:", response.status_code) + except Exception as e: + print("Exception occurred:", e) + + def post(self, url, data): + url = 'https://' + url + try: + headers = {'Content-Type': 'application/json', 'Accept': 'application/json, text/plain, */*'} + json_data = json.dumps(data) + print("Send post request to: " + url) + response = urequests.post(url, data=json_data, headers=headers) + if response.status_code == 200: + return response + else: + print("Failed to send data. Status code:", response.status_code) + print(response.text) + except Exception as e: + print("Exception occurred:", e) + diff --git a/dev_pi_pico_2405041205/main.py b/dev_pi_pico_2405041205/main.py new file mode 100644 index 0000000..964a84b --- /dev/null +++ b/dev_pi_pico_2405041205/main.py @@ -0,0 +1,57 @@ +# GrowSystem +# Author: Maik Müller (maik@muelleronlineorg) + +# WIP! +# This file should do only: +# - provide constants for settings +# - eventually necessary system settings +# - init wlan connection +# - Call base class, permitting the configured constants +import network +import urequests +from grow_system import GrowSystem +from wlan import WlanClient +from http_client import HTTPClient +from device_info import DeviceInfo + + +settings = { + 'wlan_ssid': 'Oppa-95.lan', + 'wlan_pw': '95%04-MM', + 'moisture_sensor': { + 'pin_int': 26 + }, + 'temperature_humidity_sensor': { + 'pin_int': 15 + }, + 'pump_pin_int': 24 +} + + +def wlan_scan(): + # Client-Betrieb + wlan = network.WLAN(network.STA_IF) + # WLAN-Interface aktivieren + wlan.active(True) + # WLANs ausgeben + found_wlans = wlan.scan() + return found_wlans + + +# Press the green button in the gutter to run the script. +if __name__ == '__main__': + #print(wlan_scan()) + print("Connect WLAN") + wlanClient = WlanClient(settings['wlan_ssid'], settings['wlan_pw']) + wlanClient.connect() + print("") + + di = DeviceInfo() + print("Device Infos:") + print(di.get_all_device_infos()) + print("") + + print("Start grow system") + gs = GrowSystem(settings) + gs.start() + diff --git a/dev_pi_pico_2405041205/moisture_sensor.py b/dev_pi_pico_2405041205/moisture_sensor.py new file mode 100644 index 0000000..e11ca76 --- /dev/null +++ b/dev_pi_pico_2405041205/moisture_sensor.py @@ -0,0 +1,39 @@ +# Moisture Sensor Class +from sensors import Sensors +from machine import ADC, Pin + + +class MoistureSensor(Sensors): + + sensor = None + + most_recent_values = [] + + min_raw_value = None + max_raw_value = None + + def __init__(self, sensor_data, min_raw_value=300, max_raw_value=65535): + super().__init__(sensor_data) + print("Initialize moisture sensor. Sensor pin is: " + str(sensor_data['pin_int'])) + self.sensor_pin_int = sensor_data['pin_int'] + self.min_raw_value = min_raw_value + self.max_raw_value = max_raw_value + self.sensor = ADC(Pin(self.sensor_pin_int)) + + def read(self): + self.most_recent_values = [ + { + 'type': 'moisture', + 'value': self.convert_to_moisture_percentage(self.sensor.read_u16()), + 'unit': '%' + }, + ] + + def normalize_sensor_value(self, raw_value): + return (raw_value - self.min_raw_value) / (self.max_raw_value - self.min_raw_value) + + def convert_to_moisture_percentage(self, raw_value): + normalized_value = self.normalize_sensor_value(raw_value) + return round(100 - normalized_value * 100, 1) + + \ No newline at end of file diff --git a/dev_pi_pico_2405041205/pump.py b/dev_pi_pico_2405041205/pump.py new file mode 100644 index 0000000..fc39e6d --- /dev/null +++ b/dev_pi_pico_2405041205/pump.py @@ -0,0 +1,7 @@ +from engine import Engine + + +class Pump(Engine): + + def __init__(self, engine): + super().__init__(engine) diff --git a/dev_pi_pico_2405041205/sensor_data_manager.py b/dev_pi_pico_2405041205/sensor_data_manager.py new file mode 100644 index 0000000..87dbf39 --- /dev/null +++ b/dev_pi_pico_2405041205/sensor_data_manager.py @@ -0,0 +1,20 @@ +from grow_system_api import GrowSystemApi +# from device_info import DeviceInfo + + +class SensorDataManager: + + device_info = None + + grow_system_api = None + + device_id = None + + def __init__(self, device_id): + self.grow_system_api = GrowSystemApi() + # self.device_info = DeviceInfo() + self.device_id = device_id + + def handleData(self, data): + jsonResponse = self.grow_system_api.send_measurements(self.device_id, data) + print("Response message: " + jsonResponse['message']) \ No newline at end of file diff --git a/dev_pi_pico_2405041205/sensors.py b/dev_pi_pico_2405041205/sensors.py new file mode 100644 index 0000000..23ad803 --- /dev/null +++ b/dev_pi_pico_2405041205/sensors.py @@ -0,0 +1,13 @@ +class Sensors: + # this is a parent class for the Sensor classes + sensor_pin_int = -1 + + sensor = None + + type = "unset" + + def __init__(self, settings): + self.type = settings['type'] + print("Initialize " + self.type + " sensor. Sensor pin is: " + str(settings['pin_int'])) + + \ No newline at end of file diff --git a/dev_pi_pico_2405041205/wlan.py b/dev_pi_pico_2405041205/wlan.py new file mode 100644 index 0000000..c265d8e --- /dev/null +++ b/dev_pi_pico_2405041205/wlan.py @@ -0,0 +1,39 @@ +import machine +import network +import time +# network.country('DE') + + +class WlanClient: + + ssid = '' + pw = '' + wlan = None + # Status-LED + led_onboard = machine.Pin('LED', machine.Pin.OUT) + led_onboard.value(False) + + def __init__(self, ssid, pw): + # print("Hello from wlan class") + self.ssid = ssid + self.pw = pw + self.wlan = network.WLAN(network.STA_IF) + + def connect(self): + if not self.is_connected(): + print('No WLAN connected. Connecting ...' + self.ssid + ' ' + self.pw) + self.wlan.active(True) + self.wlan.connect(self.ssid, self.pw) + for i in range(10): + if self.wlan.status() < 0 or self.wlan.status() >= 3: + break + time.sleep(1) + # led_value = self.led_onboard.value() == 1 + # self.led_onboard.value(led_value) + if self.wlan.isconnected(): + net_config = self.wlan.ifconfig() + print("NetConfig:") + print(net_config) + + def is_connected(self): + return self.wlan.isconnected() diff --git a/main.py b/main.py index 241af6c..12935fd 100644 --- a/main.py +++ b/main.py @@ -3,6 +3,7 @@ # WIP! # This file should do only: +# - first start check and actions if not configured # - provide constants for settings # - eventually necessary system settings # - init wlan connection @@ -13,6 +14,7 @@ from grow_system import GrowSystem from wlan import WlanClient from http_client import HTTPClient from device_info import DeviceInfo +from setup import Setup settings = { @@ -33,25 +35,29 @@ def wlan_scan(): wlan = network.WLAN(network.STA_IF) # WLAN-Interface aktivieren wlan.active(True) - # WLANs ausgeben + # WLANs ausgeben found_wlans = wlan.scan() return found_wlans # Press the green button in the gutter to run the script. if __name__ == '__main__': + pico_setup = Setup() + pico_setup.setup_pico() + + if false: #print(wlan_scan()) - print("Connect WLAN") - wlanClient = WlanClient(settings['wlan_ssid'], settings['wlan_pw']) - wlanClient.connect() - print("") + print("Connect WLAN") + wlanClient = WlanClient(settings['wlan_ssid'], settings['wlan_pw']) + wlanClient.connect() + print("") - di = DeviceInfo() - print("Device Infos:") - print(di.get_all_device_infos()) - print("") + di = DeviceInfo() + print("Device Infos:") + print(di.get_all_device_infos()) + print("") - print("Start grow system") - gs = GrowSystem(settings) - gs.start() + print("Start grow system") + gs = GrowSystem(settings) + gs.start() -- 2.40.1 From 1f6d92a54cac5dffde60173876604b149258326c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Sat, 4 May 2024 15:38:36 +0200 Subject: [PATCH 09/13] add setup --- device_info.py | 7 +++ engine.py | 23 +++++++++ grow_system.py | 20 +++++++- grow_system_api.py | 2 +- pump.py | 7 +++ setup.py | 113 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 engine.py create mode 100644 pump.py create mode 100644 setup.py diff --git a/device_info.py b/device_info.py index 65ab51a..a61681e 100644 --- a/device_info.py +++ b/device_info.py @@ -32,6 +32,13 @@ class DeviceInfo: # } ] + engines = [ + { + 'type': 'pump', + 'pins': [15] + } + ] + read_secs = 5 # Device Infos End diff --git a/engine.py b/engine.py new file mode 100644 index 0000000..38bf29c --- /dev/null +++ b/engine.py @@ -0,0 +1,23 @@ +from machine import Pin + + +class Engine(): + + pins = [] + + engine = None + + def __init__(self, engine): + print("Hello from Engine parent class") + print(engine) + self.pins = engine['pins'] + self.engine = Pin(self.pins[0], Pin.OUT) + + def on(self): + print("engine on") + self.engine.value(1) + + def off(self): + print("engine off") + self.engine.value(0) + diff --git a/grow_system.py b/grow_system.py index 3528ea9..3861c5a 100644 --- a/grow_system.py +++ b/grow_system.py @@ -2,6 +2,7 @@ import time from moisture_sensor import MoistureSensor from dht22 import TemperatureHumiditySensor from ambilight_sensor import AmbilightSensor +from pump import Pump from sensor_data_manager import SensorDataManager from grow_system_api import GrowSystemApi from device_info import DeviceInfo @@ -15,6 +16,8 @@ class GrowSystem: # temperature_humidity_sensor = None sensors = [] + + engines = [] most_recent_values = [] @@ -24,7 +27,8 @@ class GrowSystem: device_info = DeviceInfo() - def __init__(self, settings): + def __init__(self, settings): + # Init sensors for sensor in self.device_info.sensors: print("") print("Initialize sensor:") @@ -41,6 +45,20 @@ class GrowSystem: self.sensors.append(AmbilightSensor(sensor)) else: print("No sensor type configured for: " + sensor['type']) + + # Init engines + for engine in self.device_info.engines: + print("") + print("Initialize engine:") + print(engine) + engine_type = engine['type'] + if engine_type == 'pump': + print("Found egine of type pump") + self.engines.append(Pump(engine)) + self.engines[0].on() + time.sleep(15) + self.engines[0].off() + #if not self.moisture_sensor: # self.moisture_sensor = MoistureSensor(settings['moisture_sensor']) diff --git a/grow_system_api.py b/grow_system_api.py index 5b9ccb3..0e3376c 100644 --- a/grow_system_api.py +++ b/grow_system_api.py @@ -15,7 +15,7 @@ class GrowSystemApi: self.base_url = self.device_info.server_url def say_hello(self): - response = self.http_client.post(self.base_url + "/api/device/hello", self._get_device_data()) + response = self.http_client.post(self.base_url + "/api/device", self._get_device_data()) print(response.text) jsonResult = json.loads(response.text) print(jsonResult) diff --git a/pump.py b/pump.py new file mode 100644 index 0000000..fc39e6d --- /dev/null +++ b/pump.py @@ -0,0 +1,7 @@ +from engine import Engine + + +class Pump(Engine): + + def __init__(self, engine): + super().__init__(engine) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..2aa6cee --- /dev/null +++ b/setup.py @@ -0,0 +1,113 @@ +import network +import ujson +import ure as re +import usocket as socket +import time + +class Setup: + def __init__(self): + self.ap_ssid = "Growsystem" + self.ap_password = "12345678" + self.wlans = [] + self.selected_ssid = "" + self.wlan_password = "" + self.pin = "" + self.html = """ + + Pico Setup + +

Setup Pico

+
+ SSID:
+ Password:
+ PIN:
+ +
+ + + """ + + def scan_wlans(self): + print("Scan WLANs") + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + self.wlans = [w[0].decode() for w in wlan.scan()] + print("Found:", self.wlans) + wlan.active(False) + + def start_ap_mode(self): + self.ap = network.WLAN(network.AP_IF) + self.ap.active(True) + while self.ap.active() == False: + pass + self.ap.config(essid=self.ap_ssid, password=self.ap_password) + print("AP SSID:", self.ap.config("essid")) + # print("AP Password:", self.ap.config("password")) + + def stop_ap_mode(self): + ap = network.WLAN(network.AP_IF) + ap.active(False) + + def start_webserver(self): + addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] + s = socket.socket() + s.bind(addr) + s.listen(1) + print("Listening on", addr) + while True: + conn, addr = s.accept() + print("Got a connection from", addr) + request = conn.recv(1024) + print("Content =", request) + conn.send("HTTP/1.1 200 OK\n") + conn.send("Content-Type: text/html\n") + conn.send("Connection: close\n\n") + conn.sendall(self.html.format(''.join([''.format(w, w) for w in self.wlans]))) + conn.close() + + def parse_request(self, request): + request = request.decode() + ssid_match = re.search("ssid=([^&]+)", request) + if ssid_match: + self.selected_ssid = ssid_match.group(1) + password_match = re.search("password=([^&]+)", request) + if password_match: + self.wlan_password = password_match.group(1) + pin_match = re.search("pin=([^&]+)", request) + if pin_match: + self.pin = pin_match.group(1) + + def save_config(self): + config = { + "ssid": self.selected_ssid, + "password": self.wlan_password, + "pin": self.pin + } + with open("initial_config.py", "w") as f: + f.write("config = " + ujson.dumps(config)) + + def switch_to_client_mode(self): + ap = network.WLAN(network.AP_IF) + ap.active(False) + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + wlan.connect(self.selected_ssid, self.wlan_password) + while not wlan.isconnected(): + time.sleep(1) + print("Connected to", self.selected_ssid) + + def setup_pico(self): + print("Start PICO setup") + self.scan_wlans() + self.start_ap_mode() + self.start_webserver() + while True: + conn, addr = self.s.accept() + request = conn.recv(1024) + self.parse_request(request) + self.save_config() + conn.close() + break # Assuming only one request is handled + self.stop_ap_mode() + self.switch_to_client_mode() + -- 2.40.1 From 148928f88cfd1784db931c9f3295253aed0b94ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Mon, 6 May 2024 01:51:23 +0200 Subject: [PATCH 10/13] did a lot. upto activation working (exklusive config save) --- classes/http_request.py | 72 +++++++++++ config/app.py | 1 + grow_system_api.py | 7 ++ growsystem.py | 41 +++++++ gs/classes/http_request.py | 72 +++++++++++ gs/config/app.py | 1 + gs/config/initial_config.py | 1 + gs/device_info.py | 68 +++++++++++ gs/grow_system_api.py | 52 ++++++++ gs/growsystem.py | 54 +++++++++ gs/http_client.py | 35 ++++++ gs/little_apache.py | 110 +++++++++++++++++ gs/setup.py | 84 +++++++++++++ gs/wlan_client.py | 40 +++++++ little_apache.py | 110 +++++++++++++++++ main.py | 67 ++--------- README.md => old_version/README.md | 0 REDME.md => old_version/REDME.md | 0 .../ambilight_sensor.py | 0 .../bh1750.old_1}/__init__.py | 0 .../bh1750.old_1}/bh1750.py | 0 device_info.py => old_version/device_info.py | 0 dht22.py => old_version/dht22.py | 0 engine.py => old_version/engine.py | 0 grow_system.py => old_version/grow_system.py | 0 old_version/grow_system_api.py | 38 ++++++ old_version/http_client.py | 35 ++++++ {lib => old_version/lib}/bh1750.py | 0 old_version/main.py | 63 ++++++++++ .../moisture_sensor.py | 0 .../notes}/code_sample_moisture_sensor.txt | 0 pump.py => old_version/pump.py | 0 .../sensor_data_manager.py | 0 sensors.py => old_version/sensors.py | 0 old_version/setup.py | 113 ++++++++++++++++++ wlan.py => old_version/wlan.py | 0 setup.py | 109 +++++++---------- teststuff/main.py | 50 ++++++++ 38 files changed, 1095 insertions(+), 128 deletions(-) create mode 100644 classes/http_request.py create mode 100644 config/app.py create mode 100644 growsystem.py create mode 100644 gs/classes/http_request.py create mode 100644 gs/config/app.py create mode 100644 gs/config/initial_config.py create mode 100644 gs/device_info.py create mode 100644 gs/grow_system_api.py create mode 100644 gs/growsystem.py create mode 100644 gs/http_client.py create mode 100644 gs/little_apache.py create mode 100644 gs/setup.py create mode 100644 gs/wlan_client.py create mode 100644 little_apache.py rename README.md => old_version/README.md (100%) rename REDME.md => old_version/REDME.md (100%) rename ambilight_sensor.py => old_version/ambilight_sensor.py (100%) rename {bh1750.old_1 => old_version/bh1750.old_1}/__init__.py (100%) rename {bh1750.old_1 => old_version/bh1750.old_1}/bh1750.py (100%) rename device_info.py => old_version/device_info.py (100%) rename dht22.py => old_version/dht22.py (100%) rename engine.py => old_version/engine.py (100%) rename grow_system.py => old_version/grow_system.py (100%) create mode 100644 old_version/grow_system_api.py create mode 100644 old_version/http_client.py rename {lib => old_version/lib}/bh1750.py (100%) create mode 100644 old_version/main.py rename moisture_sensor.py => old_version/moisture_sensor.py (100%) rename {notes => old_version/notes}/code_sample_moisture_sensor.txt (100%) rename pump.py => old_version/pump.py (100%) rename sensor_data_manager.py => old_version/sensor_data_manager.py (100%) rename sensors.py => old_version/sensors.py (100%) create mode 100644 old_version/setup.py rename wlan.py => old_version/wlan.py (100%) create mode 100644 teststuff/main.py diff --git a/classes/http_request.py b/classes/http_request.py new file mode 100644 index 0000000..c85063c --- /dev/null +++ b/classes/http_request.py @@ -0,0 +1,72 @@ +import json +import ure as re + + +class HttpRequest: + + METHOD = { + "GET": "GET", + "POST": "POST" + } + + method = '' + path = '' + raw_content = '' + headers = {} + + def __init__(self, request): + self.original_request = request + # self.method = method + # self.path = path + # self.headers = headers + # self.raw_content = content + print("http request initialized") + self.parse_request(request) + + def parse_request(self, request): + # Split the request into lines + lines = request.decode().split('\r\n') + + # Extract method, path, and HTTP version from the first line + self.method, self.path, _ = lines[0].split() + + # Parse headers + for line in lines[1:]: + if not line: + break # Empty line indicates end of headers + key, value = line.split(': ', 1) + self.headers[key] = value + + # Content is assumed to be in the last line + self.raw_content = lines[-1] + + def get_content_json(self): + # Parse the POST request content into a dictionary + parsed_content = {} + pairs = self.raw_content.split('&') + for pair in pairs: + key, value = pair.split('=') + parsed_content[key] = value + + # Encode the values in the dictionary + encoded_content = {} + for key, value in parsed_content.items(): + encoded_value = re.sub(r'%([0-9A-Fa-f]{2})', lambda m: chr(int(m.group(1), 16)), value) + encoded_content[key] = encoded_value + + return encoded_content + + def __str__(self): + return { + "method": self.method, + "headers": self.headers, + "content": self.raw_content, + "content_json": self.get_content_json() + } + + + + + + + diff --git a/config/app.py b/config/app.py new file mode 100644 index 0000000..8a5b5e3 --- /dev/null +++ b/config/app.py @@ -0,0 +1 @@ +api_url = 'https://growsystem.muellerdev.kozow.com/api/' diff --git a/grow_system_api.py b/grow_system_api.py index 0e3376c..8a73310 100644 --- a/grow_system_api.py +++ b/grow_system_api.py @@ -13,6 +13,10 @@ class GrowSystemApi: def __init__(self): self.base_url = self.device_info.server_url + + def activate(self, config): + response = self.http_client.post(self.base_url + "/api/device/activate", self._get_device_data()) + return self_get_json_encoded(response.text) def say_hello(self): response = self.http_client.post(self.base_url + "/api/device", self._get_device_data()) @@ -29,3 +33,6 @@ class GrowSystemApi: def _get_device_data(self): return self.device_info.get_all_device_infos() + def _get_json_encoded(self, text): + return json.loads(text) + diff --git a/growsystem.py b/growsystem.py new file mode 100644 index 0000000..31a151c --- /dev/null +++ b/growsystem.py @@ -0,0 +1,41 @@ +from gs.setup import Setup +import os + + +class GrowSystem: + + version = "1.0" + + def __init__(self): + print("Initialize Growsystem", self.version) + if self._is_config_existing(): + print("Skip Setup. Config existing.") + elif self._is_initial_config_existing(): + self._activate() + else: + print("No config existing. Start setup ...") + self._setup() + + def _setup(self): + setup = Setup() + setup.setup_pico() + + def _activate(self): + print("Start activation!") + + def _is_config_existing(self): + return self._is_file_existing('/gs/config/config.py') + + def _is_initial_config_existing(self): + return self._is_file_existing('/gs/config/initial_config.py') + + def _is_file_existing(self, filepath): + try: + f = open(filepath, "r") + f.close() + # continue with the file. + return True + except OSError: # open failed + # handle the file open cas + return False + diff --git a/gs/classes/http_request.py b/gs/classes/http_request.py new file mode 100644 index 0000000..c85063c --- /dev/null +++ b/gs/classes/http_request.py @@ -0,0 +1,72 @@ +import json +import ure as re + + +class HttpRequest: + + METHOD = { + "GET": "GET", + "POST": "POST" + } + + method = '' + path = '' + raw_content = '' + headers = {} + + def __init__(self, request): + self.original_request = request + # self.method = method + # self.path = path + # self.headers = headers + # self.raw_content = content + print("http request initialized") + self.parse_request(request) + + def parse_request(self, request): + # Split the request into lines + lines = request.decode().split('\r\n') + + # Extract method, path, and HTTP version from the first line + self.method, self.path, _ = lines[0].split() + + # Parse headers + for line in lines[1:]: + if not line: + break # Empty line indicates end of headers + key, value = line.split(': ', 1) + self.headers[key] = value + + # Content is assumed to be in the last line + self.raw_content = lines[-1] + + def get_content_json(self): + # Parse the POST request content into a dictionary + parsed_content = {} + pairs = self.raw_content.split('&') + for pair in pairs: + key, value = pair.split('=') + parsed_content[key] = value + + # Encode the values in the dictionary + encoded_content = {} + for key, value in parsed_content.items(): + encoded_value = re.sub(r'%([0-9A-Fa-f]{2})', lambda m: chr(int(m.group(1), 16)), value) + encoded_content[key] = encoded_value + + return encoded_content + + def __str__(self): + return { + "method": self.method, + "headers": self.headers, + "content": self.raw_content, + "content_json": self.get_content_json() + } + + + + + + + diff --git a/gs/config/app.py b/gs/config/app.py new file mode 100644 index 0000000..8a5b5e3 --- /dev/null +++ b/gs/config/app.py @@ -0,0 +1 @@ +api_url = 'https://growsystem.muellerdev.kozow.com/api/' diff --git a/gs/config/initial_config.py b/gs/config/initial_config.py new file mode 100644 index 0000000..fb8b537 --- /dev/null +++ b/gs/config/initial_config.py @@ -0,0 +1 @@ +config = {"pin": "4628", "password": "95%04-MM", "ssid": "Oppa-95.lan"} \ No newline at end of file diff --git a/gs/device_info.py b/gs/device_info.py new file mode 100644 index 0000000..c88ffa7 --- /dev/null +++ b/gs/device_info.py @@ -0,0 +1,68 @@ +import network + + +class DeviceInfo: + + # Device Infos + name = "Dev Device 1" + + token = "PC]-0Bmp83h7F5#U!D6KJ(A&" + + #server_url = 'api.growsystem.muelleronline.org' + server_url = 'api.growsystem.muellerdev.kozow.com' + + wlan_ssid = 'Oppa-95.lan' + wlan_pw = '95%04-MM' + + sensors = [ + { + 'type': 'moisture', + 'pin_int': 26 + }, + { + 'type': 'ambilight', + 'pin_int': 8, # for compatibility only + 'pin_int_sda': 8, + 'pin_int_scl': 9 + }, + + + # { + # 'type': 'dht22', + # 'pin_int': 15 + # } + ] + + engines = [ + { + 'type': 'pump', + 'pins': [15] + } + ] + + read_secs = 5 + # Device Infos End + + wlan = network.WLAN(network.STA_IF) + + def get_macaddress(self): + return self._format_mac(self.wlan.config('mac').hex()) + + def get_ipaddress(self): + return self.wlan.ifconfig()[0] + + def get_all_device_infos(self): + return { + 'name': self.name, + 'mac_address': self.get_macaddress(), + 'ip_address': self.get_ipaddress(), + 'token': self.token} + + def _format_mac(self, mac): + # Split the MAC address into pairs of two characters each + pairs = [mac[i:i+2] for i in range(0, len(mac), 2)] + # Join the pairs with colons to create the formatted MAC address + formatted_mac = ":".join(pairs) + return formatted_mac + + \ No newline at end of file diff --git a/gs/grow_system_api.py b/gs/grow_system_api.py new file mode 100644 index 0000000..a40ed6b --- /dev/null +++ b/gs/grow_system_api.py @@ -0,0 +1,52 @@ +from gs.http_client import HTTPClient +from gs.device_info import DeviceInfo +from gs.wlan_client import WlanClient +import json +import gs.config.initial_config as ic + + +class GrowSystemApi: + + http_client = HTTPClient() + + device_info = DeviceInfo() + + base_url = '' + + def __init__(self): + self.base_url = self.device_info.server_url + self.connect_wifi(ic.config['ssid'], ic.config['password']) + + def activate(self, config): + data = self._get_device_data() + data.update({ + 'user_id': 1, + 'pin': config['pin'] + }) + print("activate ...", data) + response = self.http_client.post(self.base_url + "/api/device/activate", data) + return self._get_json_encoded(response.text) + + def say_hello(self): + response = self.http_client.post(self.base_url + "/api/device", self._get_device_data()) + print(response.text) + jsonResult = json.loads(response.text) + print(jsonResult) + return jsonResult; + + def send_measurements(self, device_id, data): + url = self.base_url + "/api/device/" + str(device_id) + "/sensor-log" + response = self.http_client.post(url, data) + return json.loads(response.text) + + def _get_device_data(self): + return self.device_info.get_all_device_infos() + + def _get_json_encoded(self, text): + return json.loads(text) + + def connect_wifi(self, ssid, password): + print("Connect WLAN") + self.wlan_client = WlanClient(ssid, password) + self.wlan_client.connect() + diff --git a/gs/growsystem.py b/gs/growsystem.py new file mode 100644 index 0000000..fad5818 --- /dev/null +++ b/gs/growsystem.py @@ -0,0 +1,54 @@ +from gs.setup import Setup +import os + + +class GrowSystem: + + version = "1.0" + + initial_config = None + + def __init__(self): + print("Initialize Growsystem", self.version) + + if not self._is_initial_config_existing(): + print("No config existing. Start setup ...") + self._setup() + return + + from gs.grow_system_api import GrowSystemApi as GSA + self.gsapi = GSA() + + if self._is_config_existing(): + print("Skip Setup. Config existing.") + elif self._is_initial_config_existing(): + print("Initial config only existing (no base config). Start activation ...") + self._activate() + + def _setup(self): + setup = Setup() + setup.setup_pico() + + def _activate(self): + print("Start activation!") + import gs.config.initial_config as ic + self.initial_config = ic.config + device_config = self.gsapi.activate(self.initial_config) + print("Device Config:", device_config) + + def _is_config_existing(self): + return self._is_file_existing('/gs/config/config.py') + + def _is_initial_config_existing(self): + return self._is_file_existing('/gs/config/initial_config.py') + + def _is_file_existing(self, filepath): + try: + f = open(filepath, "r") + f.close() + # continue with the file. + return True + except OSError: # open failed + # handle the file open cas + return False + diff --git a/gs/http_client.py b/gs/http_client.py new file mode 100644 index 0000000..fd197ed --- /dev/null +++ b/gs/http_client.py @@ -0,0 +1,35 @@ +import urequests +import json + +class HTTPClient: + def __init__(self): + pass + + def get(self, url): + url = 'https://' + url + try: + # headers = {'Content-Type': 'application/json'} + response = urequests.get(url) + if response.status_code == 200: + print("Data sent, got response") + return response + else: + print("Failed to get data. Status code:", response.status_code) + except Exception as e: + print("Exception occurred:", e) + + def post(self, url, data): + url = 'https://' + url + try: + headers = {'Content-Type': 'application/json', 'Accept': 'application/json, text/plain, */*'} + json_data = json.dumps(data) + print("Send post request to: " + url) + response = urequests.post(url, data=json_data, headers=headers) + if response.status_code == 200: + return response + else: + print("Failed to send data. Status code:", response.status_code) + print(response.text) + except Exception as e: + print("Exception occurred:", e) + diff --git a/gs/little_apache.py b/gs/little_apache.py new file mode 100644 index 0000000..841c96c --- /dev/null +++ b/gs/little_apache.py @@ -0,0 +1,110 @@ +import socket +from gs.classes.http_request import HttpRequest + + +class LittleApache(): + + available_wifis = [] + keep_webserver_alive = True + + + def __init__(self, net): + self.net = net + addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] + self.s = socket.socket() + self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.s.bind(addr) + self.s.listen() + # print('Listening on', addr) + + def start(self): + print("Webserver started. Connect to: " + self.net.ifconfig()[0]) + print(self.net.ifconfig()) + + while self.keep_webserver_alive: + try: + conn, addr = self.s.accept() + #print('Got a connection from', addr) + + # Receive and parse the request + request = conn.recv(1024) + # print("Request (RAW)", request) + http_request = HttpRequest(request) + self.http_request = http_request + request = str(request) + # print('Request content = %s' % request) + #try: + # request = request.split()[1] + # print('Request:', request) + #except IndexError: + # pass + response = self.response(http_request) + # Send the HTTP response and close the connection + conn.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') + conn.send(response) + conn.close() + except OSError as e: + conn.close() + print('Connection closed') + return self + + def response(self, request: HttpRequest): + #print("Webpage: ", request) + print("Request method: ", request.method, "Request path: ", request.path) + + header = f""" + + + + Growsystem + + + + """ + + footer = f""" + + + """ + + body = "" + + if self.is_path_match(request, '/test1'): + body = f""" +
Test 1!!!
+ """ + elif (self.is_path_match(request, '') or self.is_path_match(request, '/')): + options = [] + for w in self.available_wifis: + options.append(''.format(w, w)) + body = """ +

Setup Pico

+
+ SSID:
+ Password:
+ PIN:
+ +
+ """ + body = body.format(''.join(options)) + elif self.is_path_match(request, '/save', 'POST'): + print("Save config path: ", request) + self.keep_webserver_alive = False + body = """ +

Setup Pico

+
Setup abgeschlossen. Bitte ein paar Sekunden warten, dann neu starten.
+ """ + else: + body = f""" +
Unknown page
+ """ + + html = '' + html_arr = [header, body, footer] + html = html.join(html_arr) + return str(html) + + def is_path_match(self, request, path, method='GET'): + return path == request.path and method == request.method + + diff --git a/gs/setup.py b/gs/setup.py new file mode 100644 index 0000000..5b89e9d --- /dev/null +++ b/gs/setup.py @@ -0,0 +1,84 @@ +import network +import ujson +import ure as re +import usocket as socket +import time +from gs.little_apache import LittleApache + + +class Setup: + + wlans = [] + + def __init__(self): + self.ap_ssid = "Growsystem 1.0" + self.ap_password = "password" + self.wlans = [] + self.selected_ssid = "" + self.wlan_password = "" + self.pin = "" + + def scan_wlans(self): + print("Scan for WiFis") + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + self.wlans = [w[0].decode() for w in wlan.scan()] + print("Detected WiFis: ", self.wlans) + wlan.active(False) + + def start_ap_mode(self): + wlan = network.WLAN(network.STA_IF) + wlan.active(False) + wlan_config = { + "ssid": self.ap_ssid, + "pw": self.ap_password + } + print("Switch to ap mode with data:", wlan_config) + ap = network.WLAN(network.AP_IF) + ap.config(essid=self.ap_ssid, password=self.ap_password) + ap.active(True) + self.net = ap + print("Connect with your browser to:", ap.ifconfig()[0]) + + def stop_ap_mode(self): + print("Stop ap mode") + ap = network.WLAN(network.AP_IF) + ap.active(False) + + def get_initial_config_webserver(self): + self.la = LittleApache(self.net) + self.la.available_wifis = self.wlans + self.la.start() + config = self.la.http_request.get_content_json() + print("start webserver end:", config) + return config + + def save_config(self, config): + config = { + "ssid": config['ssid'], + "password": config['password'], + "pin": config['pin'] + } + print("Save config:", config) + with open("/gs/config/initial_config.py", "w") as f: + f.write("config = " + ujson.dumps(config)) + + def switch_to_client_mode(self): + print("Switch to client mode") + ap = network.WLAN(network.AP_IF) + ap.active(False) + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + wlan.connect(self.selected_ssid, self.wlan_password) + while not wlan.isconnected(): + time.sleep(1) + print("Connected to", self.selected_ssid) + + def setup_pico(self): + self.scan_wlans() + self.start_ap_mode() + config = self.get_initial_config_webserver() + self.save_config(config) + # self.stop_ap_mode() + # self.switch_to_client_mode() + diff --git a/gs/wlan_client.py b/gs/wlan_client.py new file mode 100644 index 0000000..723832f --- /dev/null +++ b/gs/wlan_client.py @@ -0,0 +1,40 @@ +import machine +import network +import time +# network.country('DE') + + +class WlanClient: + + ssid = '' + pw = '' + wlan = None + # Status-LED + led_onboard = machine.Pin('LED', machine.Pin.OUT) + led_onboard.value(False) + + def __init__(self, ssid, pw): + # print("Hello from wlan class") + self.ssid = ssid + self.pw = pw + self.wlan = network.WLAN(network.STA_IF) + + def connect(self): + if not self.is_connected(): + print('No WLAN connected. Connecting ...' + self.ssid + ' ' + self.pw) + self.wlan.active(True) + self.wlan.connect(self.ssid, self.pw) + for i in range(10): + if self.wlan.status() < 0 or self.wlan.status() >= 3: + break + time.sleep(1) + # led_value = self.led_onboard.value() == 1 + # self.led_onboard.value(led_value) + if self.wlan.isconnected(): + net_config = self.wlan.ifconfig() + print("NetConfig:") + print(net_config) + + def is_connected(self): + return self.wlan.isconnected() + diff --git a/little_apache.py b/little_apache.py new file mode 100644 index 0000000..841c96c --- /dev/null +++ b/little_apache.py @@ -0,0 +1,110 @@ +import socket +from gs.classes.http_request import HttpRequest + + +class LittleApache(): + + available_wifis = [] + keep_webserver_alive = True + + + def __init__(self, net): + self.net = net + addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] + self.s = socket.socket() + self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.s.bind(addr) + self.s.listen() + # print('Listening on', addr) + + def start(self): + print("Webserver started. Connect to: " + self.net.ifconfig()[0]) + print(self.net.ifconfig()) + + while self.keep_webserver_alive: + try: + conn, addr = self.s.accept() + #print('Got a connection from', addr) + + # Receive and parse the request + request = conn.recv(1024) + # print("Request (RAW)", request) + http_request = HttpRequest(request) + self.http_request = http_request + request = str(request) + # print('Request content = %s' % request) + #try: + # request = request.split()[1] + # print('Request:', request) + #except IndexError: + # pass + response = self.response(http_request) + # Send the HTTP response and close the connection + conn.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') + conn.send(response) + conn.close() + except OSError as e: + conn.close() + print('Connection closed') + return self + + def response(self, request: HttpRequest): + #print("Webpage: ", request) + print("Request method: ", request.method, "Request path: ", request.path) + + header = f""" + + + + Growsystem + + + + """ + + footer = f""" + + + """ + + body = "" + + if self.is_path_match(request, '/test1'): + body = f""" +
Test 1!!!
+ """ + elif (self.is_path_match(request, '') or self.is_path_match(request, '/')): + options = [] + for w in self.available_wifis: + options.append(''.format(w, w)) + body = """ +

Setup Pico

+
+ SSID:
+ Password:
+ PIN:
+ +
+ """ + body = body.format(''.join(options)) + elif self.is_path_match(request, '/save', 'POST'): + print("Save config path: ", request) + self.keep_webserver_alive = False + body = """ +

Setup Pico

+
Setup abgeschlossen. Bitte ein paar Sekunden warten, dann neu starten.
+ """ + else: + body = f""" +
Unknown page
+ """ + + html = '' + html_arr = [header, body, footer] + html = html.join(html_arr) + return str(html) + + def is_path_match(self, request, path, method='GET'): + return path == request.path and method == request.method + + diff --git a/main.py b/main.py index 12935fd..71b2e28 100644 --- a/main.py +++ b/main.py @@ -1,63 +1,12 @@ -# GrowSystem -# Author: Maik Müller (maik@muelleronlineorg) - -# WIP! -# This file should do only: -# - first start check and actions if not configured -# - provide constants for settings -# - eventually necessary system settings -# - init wlan connection -# - Call base class, permitting the configured constants -import network -import urequests -from grow_system import GrowSystem -from wlan import WlanClient -from http_client import HTTPClient -from device_info import DeviceInfo -from setup import Setup +## Only start grow system +from gs.growsystem import GrowSystem +from time import sleep -settings = { - 'wlan_ssid': 'Oppa-95.lan', - 'wlan_pw': '95%04-MM', - 'moisture_sensor': { - 'pin_int': 26 - }, - 'temperature_humidity_sensor': { - 'pin_int': 15 - }, - 'pump_pin_int': 24 -} - - -def wlan_scan(): - # Client-Betrieb - wlan = network.WLAN(network.STA_IF) - # WLAN-Interface aktivieren - wlan.active(True) - # WLANs ausgeben - found_wlans = wlan.scan() - return found_wlans - - -# Press the green button in the gutter to run the script. if __name__ == '__main__': - pico_setup = Setup() - pico_setup.setup_pico() + gs = GrowSystem() - if false: - #print(wlan_scan()) - print("Connect WLAN") - wlanClient = WlanClient(settings['wlan_ssid'], settings['wlan_pw']) - wlanClient.connect() - print("") - - di = DeviceInfo() - print("Device Infos:") - print(di.get_all_device_infos()) - print("") - - print("Start grow system") - gs = GrowSystem(settings) - gs.start() - + while True: + print("Keep running in main.py") + sleep(5) + diff --git a/README.md b/old_version/README.md similarity index 100% rename from README.md rename to old_version/README.md diff --git a/REDME.md b/old_version/REDME.md similarity index 100% rename from REDME.md rename to old_version/REDME.md diff --git a/ambilight_sensor.py b/old_version/ambilight_sensor.py similarity index 100% rename from ambilight_sensor.py rename to old_version/ambilight_sensor.py diff --git a/bh1750.old_1/__init__.py b/old_version/bh1750.old_1/__init__.py similarity index 100% rename from bh1750.old_1/__init__.py rename to old_version/bh1750.old_1/__init__.py diff --git a/bh1750.old_1/bh1750.py b/old_version/bh1750.old_1/bh1750.py similarity index 100% rename from bh1750.old_1/bh1750.py rename to old_version/bh1750.old_1/bh1750.py diff --git a/device_info.py b/old_version/device_info.py similarity index 100% rename from device_info.py rename to old_version/device_info.py diff --git a/dht22.py b/old_version/dht22.py similarity index 100% rename from dht22.py rename to old_version/dht22.py diff --git a/engine.py b/old_version/engine.py similarity index 100% rename from engine.py rename to old_version/engine.py diff --git a/grow_system.py b/old_version/grow_system.py similarity index 100% rename from grow_system.py rename to old_version/grow_system.py diff --git a/old_version/grow_system_api.py b/old_version/grow_system_api.py new file mode 100644 index 0000000..8a73310 --- /dev/null +++ b/old_version/grow_system_api.py @@ -0,0 +1,38 @@ +from http_client import HTTPClient +from device_info import DeviceInfo +import json + + +class GrowSystemApi: + + http_client = HTTPClient() + + device_info = DeviceInfo() + + base_url = '' + + def __init__(self): + self.base_url = self.device_info.server_url + + def activate(self, config): + response = self.http_client.post(self.base_url + "/api/device/activate", self._get_device_data()) + return self_get_json_encoded(response.text) + + def say_hello(self): + response = self.http_client.post(self.base_url + "/api/device", self._get_device_data()) + print(response.text) + jsonResult = json.loads(response.text) + print(jsonResult) + return jsonResult; + + def send_measurements(self, device_id, data): + url = self.base_url + "/api/device/" + str(device_id) + "/sensor-log" + response = self.http_client.post(url, data) + return json.loads(response.text) + + def _get_device_data(self): + return self.device_info.get_all_device_infos() + + def _get_json_encoded(self, text): + return json.loads(text) + diff --git a/old_version/http_client.py b/old_version/http_client.py new file mode 100644 index 0000000..fd197ed --- /dev/null +++ b/old_version/http_client.py @@ -0,0 +1,35 @@ +import urequests +import json + +class HTTPClient: + def __init__(self): + pass + + def get(self, url): + url = 'https://' + url + try: + # headers = {'Content-Type': 'application/json'} + response = urequests.get(url) + if response.status_code == 200: + print("Data sent, got response") + return response + else: + print("Failed to get data. Status code:", response.status_code) + except Exception as e: + print("Exception occurred:", e) + + def post(self, url, data): + url = 'https://' + url + try: + headers = {'Content-Type': 'application/json', 'Accept': 'application/json, text/plain, */*'} + json_data = json.dumps(data) + print("Send post request to: " + url) + response = urequests.post(url, data=json_data, headers=headers) + if response.status_code == 200: + return response + else: + print("Failed to send data. Status code:", response.status_code) + print(response.text) + except Exception as e: + print("Exception occurred:", e) + diff --git a/lib/bh1750.py b/old_version/lib/bh1750.py similarity index 100% rename from lib/bh1750.py rename to old_version/lib/bh1750.py diff --git a/old_version/main.py b/old_version/main.py new file mode 100644 index 0000000..12935fd --- /dev/null +++ b/old_version/main.py @@ -0,0 +1,63 @@ +# GrowSystem +# Author: Maik Müller (maik@muelleronlineorg) + +# WIP! +# This file should do only: +# - first start check and actions if not configured +# - provide constants for settings +# - eventually necessary system settings +# - init wlan connection +# - Call base class, permitting the configured constants +import network +import urequests +from grow_system import GrowSystem +from wlan import WlanClient +from http_client import HTTPClient +from device_info import DeviceInfo +from setup import Setup + + +settings = { + 'wlan_ssid': 'Oppa-95.lan', + 'wlan_pw': '95%04-MM', + 'moisture_sensor': { + 'pin_int': 26 + }, + 'temperature_humidity_sensor': { + 'pin_int': 15 + }, + 'pump_pin_int': 24 +} + + +def wlan_scan(): + # Client-Betrieb + wlan = network.WLAN(network.STA_IF) + # WLAN-Interface aktivieren + wlan.active(True) + # WLANs ausgeben + found_wlans = wlan.scan() + return found_wlans + + +# Press the green button in the gutter to run the script. +if __name__ == '__main__': + pico_setup = Setup() + pico_setup.setup_pico() + + if false: + #print(wlan_scan()) + print("Connect WLAN") + wlanClient = WlanClient(settings['wlan_ssid'], settings['wlan_pw']) + wlanClient.connect() + print("") + + di = DeviceInfo() + print("Device Infos:") + print(di.get_all_device_infos()) + print("") + + print("Start grow system") + gs = GrowSystem(settings) + gs.start() + diff --git a/moisture_sensor.py b/old_version/moisture_sensor.py similarity index 100% rename from moisture_sensor.py rename to old_version/moisture_sensor.py diff --git a/notes/code_sample_moisture_sensor.txt b/old_version/notes/code_sample_moisture_sensor.txt similarity index 100% rename from notes/code_sample_moisture_sensor.txt rename to old_version/notes/code_sample_moisture_sensor.txt diff --git a/pump.py b/old_version/pump.py similarity index 100% rename from pump.py rename to old_version/pump.py diff --git a/sensor_data_manager.py b/old_version/sensor_data_manager.py similarity index 100% rename from sensor_data_manager.py rename to old_version/sensor_data_manager.py diff --git a/sensors.py b/old_version/sensors.py similarity index 100% rename from sensors.py rename to old_version/sensors.py diff --git a/old_version/setup.py b/old_version/setup.py new file mode 100644 index 0000000..2aa6cee --- /dev/null +++ b/old_version/setup.py @@ -0,0 +1,113 @@ +import network +import ujson +import ure as re +import usocket as socket +import time + +class Setup: + def __init__(self): + self.ap_ssid = "Growsystem" + self.ap_password = "12345678" + self.wlans = [] + self.selected_ssid = "" + self.wlan_password = "" + self.pin = "" + self.html = """ + + Pico Setup + +

Setup Pico

+
+ SSID:
+ Password:
+ PIN:
+ +
+ + + """ + + def scan_wlans(self): + print("Scan WLANs") + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + self.wlans = [w[0].decode() for w in wlan.scan()] + print("Found:", self.wlans) + wlan.active(False) + + def start_ap_mode(self): + self.ap = network.WLAN(network.AP_IF) + self.ap.active(True) + while self.ap.active() == False: + pass + self.ap.config(essid=self.ap_ssid, password=self.ap_password) + print("AP SSID:", self.ap.config("essid")) + # print("AP Password:", self.ap.config("password")) + + def stop_ap_mode(self): + ap = network.WLAN(network.AP_IF) + ap.active(False) + + def start_webserver(self): + addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] + s = socket.socket() + s.bind(addr) + s.listen(1) + print("Listening on", addr) + while True: + conn, addr = s.accept() + print("Got a connection from", addr) + request = conn.recv(1024) + print("Content =", request) + conn.send("HTTP/1.1 200 OK\n") + conn.send("Content-Type: text/html\n") + conn.send("Connection: close\n\n") + conn.sendall(self.html.format(''.join([''.format(w, w) for w in self.wlans]))) + conn.close() + + def parse_request(self, request): + request = request.decode() + ssid_match = re.search("ssid=([^&]+)", request) + if ssid_match: + self.selected_ssid = ssid_match.group(1) + password_match = re.search("password=([^&]+)", request) + if password_match: + self.wlan_password = password_match.group(1) + pin_match = re.search("pin=([^&]+)", request) + if pin_match: + self.pin = pin_match.group(1) + + def save_config(self): + config = { + "ssid": self.selected_ssid, + "password": self.wlan_password, + "pin": self.pin + } + with open("initial_config.py", "w") as f: + f.write("config = " + ujson.dumps(config)) + + def switch_to_client_mode(self): + ap = network.WLAN(network.AP_IF) + ap.active(False) + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + wlan.connect(self.selected_ssid, self.wlan_password) + while not wlan.isconnected(): + time.sleep(1) + print("Connected to", self.selected_ssid) + + def setup_pico(self): + print("Start PICO setup") + self.scan_wlans() + self.start_ap_mode() + self.start_webserver() + while True: + conn, addr = self.s.accept() + request = conn.recv(1024) + self.parse_request(request) + self.save_config() + conn.close() + break # Assuming only one request is handled + self.stop_ap_mode() + self.switch_to_client_mode() + diff --git a/wlan.py b/old_version/wlan.py similarity index 100% rename from wlan.py rename to old_version/wlan.py diff --git a/setup.py b/setup.py index 2aa6cee..5b89e9d 100644 --- a/setup.py +++ b/setup.py @@ -3,90 +3,68 @@ import ujson import ure as re import usocket as socket import time +from gs.little_apache import LittleApache + class Setup: + + wlans = [] + def __init__(self): - self.ap_ssid = "Growsystem" - self.ap_password = "12345678" + self.ap_ssid = "Growsystem 1.0" + self.ap_password = "password" self.wlans = [] self.selected_ssid = "" self.wlan_password = "" self.pin = "" - self.html = """ - - Pico Setup - -

Setup Pico

-
- SSID:
- Password:
- PIN:
- -
- - - """ def scan_wlans(self): - print("Scan WLANs") + print("Scan for WiFis") wlan = network.WLAN(network.STA_IF) wlan.active(True) self.wlans = [w[0].decode() for w in wlan.scan()] - print("Found:", self.wlans) + print("Detected WiFis: ", self.wlans) wlan.active(False) def start_ap_mode(self): - self.ap = network.WLAN(network.AP_IF) - self.ap.active(True) - while self.ap.active() == False: - pass - self.ap.config(essid=self.ap_ssid, password=self.ap_password) - print("AP SSID:", self.ap.config("essid")) - # print("AP Password:", self.ap.config("password")) + wlan = network.WLAN(network.STA_IF) + wlan.active(False) + wlan_config = { + "ssid": self.ap_ssid, + "pw": self.ap_password + } + print("Switch to ap mode with data:", wlan_config) + ap = network.WLAN(network.AP_IF) + ap.config(essid=self.ap_ssid, password=self.ap_password) + ap.active(True) + self.net = ap + print("Connect with your browser to:", ap.ifconfig()[0]) def stop_ap_mode(self): + print("Stop ap mode") ap = network.WLAN(network.AP_IF) ap.active(False) - def start_webserver(self): - addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] - s = socket.socket() - s.bind(addr) - s.listen(1) - print("Listening on", addr) - while True: - conn, addr = s.accept() - print("Got a connection from", addr) - request = conn.recv(1024) - print("Content =", request) - conn.send("HTTP/1.1 200 OK\n") - conn.send("Content-Type: text/html\n") - conn.send("Connection: close\n\n") - conn.sendall(self.html.format(''.join([''.format(w, w) for w in self.wlans]))) - conn.close() + def get_initial_config_webserver(self): + self.la = LittleApache(self.net) + self.la.available_wifis = self.wlans + self.la.start() + config = self.la.http_request.get_content_json() + print("start webserver end:", config) + return config - def parse_request(self, request): - request = request.decode() - ssid_match = re.search("ssid=([^&]+)", request) - if ssid_match: - self.selected_ssid = ssid_match.group(1) - password_match = re.search("password=([^&]+)", request) - if password_match: - self.wlan_password = password_match.group(1) - pin_match = re.search("pin=([^&]+)", request) - if pin_match: - self.pin = pin_match.group(1) - - def save_config(self): + def save_config(self, config): config = { - "ssid": self.selected_ssid, - "password": self.wlan_password, - "pin": self.pin + "ssid": config['ssid'], + "password": config['password'], + "pin": config['pin'] } - with open("initial_config.py", "w") as f: + print("Save config:", config) + with open("/gs/config/initial_config.py", "w") as f: f.write("config = " + ujson.dumps(config)) def switch_to_client_mode(self): + print("Switch to client mode") ap = network.WLAN(network.AP_IF) ap.active(False) wlan = network.WLAN(network.STA_IF) @@ -97,17 +75,10 @@ class Setup: print("Connected to", self.selected_ssid) def setup_pico(self): - print("Start PICO setup") self.scan_wlans() self.start_ap_mode() - self.start_webserver() - while True: - conn, addr = self.s.accept() - request = conn.recv(1024) - self.parse_request(request) - self.save_config() - conn.close() - break # Assuming only one request is handled - self.stop_ap_mode() - self.switch_to_client_mode() + config = self.get_initial_config_webserver() + self.save_config(config) + # self.stop_ap_mode() + # self.switch_to_client_mode() diff --git a/teststuff/main.py b/teststuff/main.py new file mode 100644 index 0000000..27c3051 --- /dev/null +++ b/teststuff/main.py @@ -0,0 +1,50 @@ +import network +import time +import socket + +ssid="Growsystem" +password="12345678" + +def web_page(): + html = """ +

Hello World

+ """ + return html + +# if you do not see the network you may have to power cycle +# unplug your pico w for 10 seconds and plug it in again +def ap_mode(ssid, password): + """ + Description: This is a function to activate AP mode + + Parameters: + + ssid[str]: The name of your internet connection + password[str]: Password for your internet connection + + Returns: Nada + """ + # Just making our internet connection + ap = network.WLAN(network.AP_IF) + ap.config(essid=ssid, password=password) + ap.active(True) + + while ap.active() == False: + pass + print('AP Mode Is Active, You can Now Connect') + print('IP Address To Connect to:: ' + ap.ifconfig()[0]) + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #creating socket object + s.bind(('', 80)) + s.listen(5) + + while True: + conn, addr = s.accept() + print('Got a connection from %s' % str(addr)) + request = conn.recv(1024) + print('Content = %s' % str(request)) + response = web_page() + conn.send(response) + conn.close() + +ap_mode('Growsystem95','PASSWORD') \ No newline at end of file -- 2.40.1 From af98f900858e4531e3c769988007758b47adff58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Mon, 6 May 2024 17:31:52 +0200 Subject: [PATCH 11/13] activation working so far --- grow_system_api.py | 38 ------------- growsystem.py | 41 -------------- gs/config/device_config.py | 1 + gs/config/initial_config.py | 2 +- gs/device_info.py | 10 ++++ gs/grow_system_api.py | 4 ++ gs/growsystem.py | 10 +++- little_apache.py | 110 ------------------------------------ setup.py | 84 --------------------------- 9 files changed, 25 insertions(+), 275 deletions(-) delete mode 100644 grow_system_api.py delete mode 100644 growsystem.py create mode 100644 gs/config/device_config.py delete mode 100644 little_apache.py delete mode 100644 setup.py diff --git a/grow_system_api.py b/grow_system_api.py deleted file mode 100644 index 8a73310..0000000 --- a/grow_system_api.py +++ /dev/null @@ -1,38 +0,0 @@ -from http_client import HTTPClient -from device_info import DeviceInfo -import json - - -class GrowSystemApi: - - http_client = HTTPClient() - - device_info = DeviceInfo() - - base_url = '' - - def __init__(self): - self.base_url = self.device_info.server_url - - def activate(self, config): - response = self.http_client.post(self.base_url + "/api/device/activate", self._get_device_data()) - return self_get_json_encoded(response.text) - - def say_hello(self): - response = self.http_client.post(self.base_url + "/api/device", self._get_device_data()) - print(response.text) - jsonResult = json.loads(response.text) - print(jsonResult) - return jsonResult; - - def send_measurements(self, device_id, data): - url = self.base_url + "/api/device/" + str(device_id) + "/sensor-log" - response = self.http_client.post(url, data) - return json.loads(response.text) - - def _get_device_data(self): - return self.device_info.get_all_device_infos() - - def _get_json_encoded(self, text): - return json.loads(text) - diff --git a/growsystem.py b/growsystem.py deleted file mode 100644 index 31a151c..0000000 --- a/growsystem.py +++ /dev/null @@ -1,41 +0,0 @@ -from gs.setup import Setup -import os - - -class GrowSystem: - - version = "1.0" - - def __init__(self): - print("Initialize Growsystem", self.version) - if self._is_config_existing(): - print("Skip Setup. Config existing.") - elif self._is_initial_config_existing(): - self._activate() - else: - print("No config existing. Start setup ...") - self._setup() - - def _setup(self): - setup = Setup() - setup.setup_pico() - - def _activate(self): - print("Start activation!") - - def _is_config_existing(self): - return self._is_file_existing('/gs/config/config.py') - - def _is_initial_config_existing(self): - return self._is_file_existing('/gs/config/initial_config.py') - - def _is_file_existing(self, filepath): - try: - f = open(filepath, "r") - f.close() - # continue with the file. - return True - except OSError: # open failed - # handle the file open cas - return False - diff --git a/gs/config/device_config.py b/gs/config/device_config.py new file mode 100644 index 0000000..4111c92 --- /dev/null +++ b/gs/config/device_config.py @@ -0,0 +1 @@ +sensors = [{"pin_int_sda": 8, "type": "ambilight", "pin_int": 8, "pin_int_scl": 9}, {"pin_int": 15, "type": "dht22"}, {"pin_int": 26, "type": "moisture"}] \ No newline at end of file diff --git a/gs/config/initial_config.py b/gs/config/initial_config.py index fb8b537..9a3b791 100644 --- a/gs/config/initial_config.py +++ b/gs/config/initial_config.py @@ -1 +1 @@ -config = {"pin": "4628", "password": "95%04-MM", "ssid": "Oppa-95.lan"} \ No newline at end of file +config = {"pin": "1234", "password": "95%04-MM", "ssid": "Oppa-95.lan"} \ No newline at end of file diff --git a/gs/device_info.py b/gs/device_info.py index c88ffa7..eb4c1da 100644 --- a/gs/device_info.py +++ b/gs/device_info.py @@ -1,4 +1,5 @@ import network +import json class DeviceInfo: @@ -58,6 +59,9 @@ class DeviceInfo: 'ip_address': self.get_ipaddress(), 'token': self.token} + def config(self): + return self._loadConfig() + def _format_mac(self, mac): # Split the MAC address into pairs of two characters each pairs = [mac[i:i+2] for i in range(0, len(mac), 2)] @@ -65,4 +69,10 @@ class DeviceInfo: formatted_mac = ":".join(pairs) return formatted_mac + def _loadConfig(self): + with open('/gs/config/sensors.py', 'r') as file: + json_content = file.read() + return json.loads(json_content) + + \ No newline at end of file diff --git a/gs/grow_system_api.py b/gs/grow_system_api.py index a40ed6b..fa7ab66 100644 --- a/gs/grow_system_api.py +++ b/gs/grow_system_api.py @@ -17,6 +17,10 @@ class GrowSystemApi: self.base_url = self.device_info.server_url self.connect_wifi(ic.config['ssid'], ic.config['password']) + # config = self.device_info.config() + # print("Config:", config) + # print("Test", config['test']) + def activate(self, config): data = self._get_device_data() data.update({ diff --git a/gs/growsystem.py b/gs/growsystem.py index fad5818..26885ad 100644 --- a/gs/growsystem.py +++ b/gs/growsystem.py @@ -1,5 +1,6 @@ from gs.setup import Setup import os +import ujson class GrowSystem: @@ -34,7 +35,14 @@ class GrowSystem: import gs.config.initial_config as ic self.initial_config = ic.config device_config = self.gsapi.activate(self.initial_config) - print("Device Config:", device_config) + #print("Device Config:", device_config['data']) + sensors = device_config['data']['sensors'] + sensor_configs = [] + for sensor in sensors: + sensor_configs.append(sensor['config']) + print(sensor['config']) + with open("/gs/config/device_config.py", "w") as f: + f.write("sensors = " + ujson.dumps(sensor_configs)) def _is_config_existing(self): return self._is_file_existing('/gs/config/config.py') diff --git a/little_apache.py b/little_apache.py deleted file mode 100644 index 841c96c..0000000 --- a/little_apache.py +++ /dev/null @@ -1,110 +0,0 @@ -import socket -from gs.classes.http_request import HttpRequest - - -class LittleApache(): - - available_wifis = [] - keep_webserver_alive = True - - - def __init__(self, net): - self.net = net - addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] - self.s = socket.socket() - self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.s.bind(addr) - self.s.listen() - # print('Listening on', addr) - - def start(self): - print("Webserver started. Connect to: " + self.net.ifconfig()[0]) - print(self.net.ifconfig()) - - while self.keep_webserver_alive: - try: - conn, addr = self.s.accept() - #print('Got a connection from', addr) - - # Receive and parse the request - request = conn.recv(1024) - # print("Request (RAW)", request) - http_request = HttpRequest(request) - self.http_request = http_request - request = str(request) - # print('Request content = %s' % request) - #try: - # request = request.split()[1] - # print('Request:', request) - #except IndexError: - # pass - response = self.response(http_request) - # Send the HTTP response and close the connection - conn.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') - conn.send(response) - conn.close() - except OSError as e: - conn.close() - print('Connection closed') - return self - - def response(self, request: HttpRequest): - #print("Webpage: ", request) - print("Request method: ", request.method, "Request path: ", request.path) - - header = f""" - - - - Growsystem - - - - """ - - footer = f""" - - - """ - - body = "" - - if self.is_path_match(request, '/test1'): - body = f""" -
Test 1!!!
- """ - elif (self.is_path_match(request, '') or self.is_path_match(request, '/')): - options = [] - for w in self.available_wifis: - options.append(''.format(w, w)) - body = """ -

Setup Pico

-
- SSID:
- Password:
- PIN:
- -
- """ - body = body.format(''.join(options)) - elif self.is_path_match(request, '/save', 'POST'): - print("Save config path: ", request) - self.keep_webserver_alive = False - body = """ -

Setup Pico

-
Setup abgeschlossen. Bitte ein paar Sekunden warten, dann neu starten.
- """ - else: - body = f""" -
Unknown page
- """ - - html = '' - html_arr = [header, body, footer] - html = html.join(html_arr) - return str(html) - - def is_path_match(self, request, path, method='GET'): - return path == request.path and method == request.method - - diff --git a/setup.py b/setup.py deleted file mode 100644 index 5b89e9d..0000000 --- a/setup.py +++ /dev/null @@ -1,84 +0,0 @@ -import network -import ujson -import ure as re -import usocket as socket -import time -from gs.little_apache import LittleApache - - -class Setup: - - wlans = [] - - def __init__(self): - self.ap_ssid = "Growsystem 1.0" - self.ap_password = "password" - self.wlans = [] - self.selected_ssid = "" - self.wlan_password = "" - self.pin = "" - - def scan_wlans(self): - print("Scan for WiFis") - wlan = network.WLAN(network.STA_IF) - wlan.active(True) - self.wlans = [w[0].decode() for w in wlan.scan()] - print("Detected WiFis: ", self.wlans) - wlan.active(False) - - def start_ap_mode(self): - wlan = network.WLAN(network.STA_IF) - wlan.active(False) - wlan_config = { - "ssid": self.ap_ssid, - "pw": self.ap_password - } - print("Switch to ap mode with data:", wlan_config) - ap = network.WLAN(network.AP_IF) - ap.config(essid=self.ap_ssid, password=self.ap_password) - ap.active(True) - self.net = ap - print("Connect with your browser to:", ap.ifconfig()[0]) - - def stop_ap_mode(self): - print("Stop ap mode") - ap = network.WLAN(network.AP_IF) - ap.active(False) - - def get_initial_config_webserver(self): - self.la = LittleApache(self.net) - self.la.available_wifis = self.wlans - self.la.start() - config = self.la.http_request.get_content_json() - print("start webserver end:", config) - return config - - def save_config(self, config): - config = { - "ssid": config['ssid'], - "password": config['password'], - "pin": config['pin'] - } - print("Save config:", config) - with open("/gs/config/initial_config.py", "w") as f: - f.write("config = " + ujson.dumps(config)) - - def switch_to_client_mode(self): - print("Switch to client mode") - ap = network.WLAN(network.AP_IF) - ap.active(False) - wlan = network.WLAN(network.STA_IF) - wlan.active(True) - wlan.connect(self.selected_ssid, self.wlan_password) - while not wlan.isconnected(): - time.sleep(1) - print("Connected to", self.selected_ssid) - - def setup_pico(self): - self.scan_wlans() - self.start_ap_mode() - config = self.get_initial_config_webserver() - self.save_config(config) - # self.stop_ap_mode() - # self.switch_to_client_mode() - -- 2.40.1 From 3c8b59f709f0c2ac088249505471a58be29c194f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Tue, 7 May 2024 13:23:05 +0200 Subject: [PATCH 12/13] code ready --- gs/classes/a_sensors.py | 13 ++++ gs/classes/sensors.py | 13 ++++ gs/classes/sensors/ambilight_sensor.py | 35 ++++++++++ gs/classes/sensors/dht22.py | 37 +++++++++++ gs/classes/sensors/moisture_sensor.py | 39 +++++++++++ gs/config/app.py | 3 +- gs/config/device_config.json | 1 + gs/config/device_config.py | 1 - gs/config/initial_config.py | 2 +- gs/device_info.py | 82 ++++++++++------------- gs/exceptions/not_subscriptable_error.py | 2 + gs/grow_system_api.py | 12 +++- gs/growsystem.py | 83 +++++++++++++++++++++--- gs/http_client.py | 9 +-- gs/little_apache.py | 5 +- gs/sensor_data_manager.py | 24 +++++++ gs/setup.py | 5 +- lib/bh1750.py | 62 ++++++++++++++++++ main.py | 3 +- 19 files changed, 362 insertions(+), 69 deletions(-) create mode 100644 gs/classes/a_sensors.py create mode 100644 gs/classes/sensors.py create mode 100644 gs/classes/sensors/ambilight_sensor.py create mode 100644 gs/classes/sensors/dht22.py create mode 100644 gs/classes/sensors/moisture_sensor.py create mode 100644 gs/config/device_config.json delete mode 100644 gs/config/device_config.py create mode 100644 gs/exceptions/not_subscriptable_error.py create mode 100644 gs/sensor_data_manager.py create mode 100644 lib/bh1750.py diff --git a/gs/classes/a_sensors.py b/gs/classes/a_sensors.py new file mode 100644 index 0000000..af4244e --- /dev/null +++ b/gs/classes/a_sensors.py @@ -0,0 +1,13 @@ +class Sensors: + # this is a parent class for the Sensor classes + sensor_pin_int = -1 + + sensor = None + + type = "unset" + + def __init__(self, settings): + self.type = settings['type'] + print("Initialize " + self.type + " sensor. Sensor pin is: " + str(settings['pin_int'])) + + diff --git a/gs/classes/sensors.py b/gs/classes/sensors.py new file mode 100644 index 0000000..af4244e --- /dev/null +++ b/gs/classes/sensors.py @@ -0,0 +1,13 @@ +class Sensors: + # this is a parent class for the Sensor classes + sensor_pin_int = -1 + + sensor = None + + type = "unset" + + def __init__(self, settings): + self.type = settings['type'] + print("Initialize " + self.type + " sensor. Sensor pin is: " + str(settings['pin_int'])) + + diff --git a/gs/classes/sensors/ambilight_sensor.py b/gs/classes/sensors/ambilight_sensor.py new file mode 100644 index 0000000..df1d966 --- /dev/null +++ b/gs/classes/sensors/ambilight_sensor.py @@ -0,0 +1,35 @@ +from gs.classes.a_sensors import Sensors +from machine import Pin, I2C +from utime import sleep +from lib.bh1750 import BH1750 + + +class AmbilightSensor(Sensors): + + + most_recent_values = [] + + def __init__(self, settings): + super().__init__(settings) + print(settings) # TODO remove + self.sensor_pin_int = settings['pin_int'] + # self.sensor = DHT22(Pin(self.sensor_pin_int, Pin.IN, Pin.PULL_UP)) + self.sensor = BH1750(I2C(0, sda=Pin(settings['pin_int_sda']), scl=Pin(settings['pin_int_scl']))) + + def read(self): + try: + measurement = self.sensor.luminance(BH1750.ONCE_HIRES_1) + print("ambilight ..") + print(measurement) + self.most_recent_values = [ + { + 'type': 'ambilight', + 'value': measurement, + 'unit': '-' + }, + ] + except OSError: + print('Ambilight Error reading temperature/humidity. Check wires') + print() + + diff --git a/gs/classes/sensors/dht22.py b/gs/classes/sensors/dht22.py new file mode 100644 index 0000000..464b31d --- /dev/null +++ b/gs/classes/sensors/dht22.py @@ -0,0 +1,37 @@ +from gs.classes.a_sensors import Sensors +from dht import DHT22 +from machine import ADC, Pin + + +class TemperatureHumiditySensor(Sensors): + + sensor = None + + most_recent_values = [] + + def __init__(self, settings): + super().__init__(settings) + print("Initialize dht22 sensor. Sensor pin is: " + str(settings['pin_int'])) + print(settings) + self.sensor_pin_int = settings['pin_int'] + self.sensor = DHT22(Pin(self.sensor_pin_int, Pin.IN, Pin.PULL_UP)) + + def read(self): + try: + self.sensor.measure() + self.most_recent_values = [ + { + 'type': 'temperature', + 'value': self.sensor.temperature(), + 'unit': 'C' + }, + { + 'type': 'humidity', + 'value': self.sensor.humidity(), + 'unit': '%' + } + ] + except OSError: + print('DHT22 Error reading temperature/humidity. Check wires') + print() + diff --git a/gs/classes/sensors/moisture_sensor.py b/gs/classes/sensors/moisture_sensor.py new file mode 100644 index 0000000..145cf9a --- /dev/null +++ b/gs/classes/sensors/moisture_sensor.py @@ -0,0 +1,39 @@ +# Moisture Sensor Class +from gs.classes.a_sensors import Sensors +from machine import ADC, Pin + + +class MoistureSensor(Sensors): + + sensor = None + + most_recent_values = [] + + min_raw_value = None + max_raw_value = None + + def __init__(self, sensor_data, min_raw_value=300, max_raw_value=65535): + super().__init__(sensor_data) + print("Initialize moisture sensor. Sensor pin is: " + str(sensor_data['pin_int'])) + self.sensor_pin_int = sensor_data['pin_int'] + self.min_raw_value = min_raw_value + self.max_raw_value = max_raw_value + self.sensor = ADC(Pin(self.sensor_pin_int)) + + def read(self): + self.most_recent_values = [ + { + 'type': 'moisture', + 'value': self.convert_to_moisture_percentage(self.sensor.read_u16()), + 'unit': '%' + }, + ] + + def normalize_sensor_value(self, raw_value): + return (raw_value - self.min_raw_value) / (self.max_raw_value - self.min_raw_value) + + def convert_to_moisture_percentage(self, raw_value): + normalized_value = self.normalize_sensor_value(raw_value) + return round(100 - normalized_value * 100, 1) + + diff --git a/gs/config/app.py b/gs/config/app.py index 8a5b5e3..f066dbd 100644 --- a/gs/config/app.py +++ b/gs/config/app.py @@ -1 +1,2 @@ -api_url = 'https://growsystem.muellerdev.kozow.com/api/' +api_url = 'api.growsystem.muellerdev.kozow.com' +read_secs = 1 * 60 diff --git a/gs/config/device_config.json b/gs/config/device_config.json new file mode 100644 index 0000000..901d060 --- /dev/null +++ b/gs/config/device_config.json @@ -0,0 +1 @@ +{"sensors": [{"pin_int": 15, "type": "dht22"}, {"pin_int": 26, "type": "moisture"}], "device_id": 9, "name": "Fulltest1", "token": "uStIrOgScrpbUr0Y", "user_id": 1} \ No newline at end of file diff --git a/gs/config/device_config.py b/gs/config/device_config.py deleted file mode 100644 index 4111c92..0000000 --- a/gs/config/device_config.py +++ /dev/null @@ -1 +0,0 @@ -sensors = [{"pin_int_sda": 8, "type": "ambilight", "pin_int": 8, "pin_int_scl": 9}, {"pin_int": 15, "type": "dht22"}, {"pin_int": 26, "type": "moisture"}] \ No newline at end of file diff --git a/gs/config/initial_config.py b/gs/config/initial_config.py index 9a3b791..9cd4fe6 100644 --- a/gs/config/initial_config.py +++ b/gs/config/initial_config.py @@ -1 +1 @@ -config = {"pin": "1234", "password": "95%04-MM", "ssid": "Oppa-95.lan"} \ No newline at end of file +config = {"ssid": "Oppa-95.lan", "user_id": "1", "password": "95%04-MM", "pin": 9534} \ No newline at end of file diff --git a/gs/device_info.py b/gs/device_info.py index eb4c1da..93f89aa 100644 --- a/gs/device_info.py +++ b/gs/device_info.py @@ -4,47 +4,9 @@ import json class DeviceInfo: - # Device Infos - name = "Dev Device 1" - - token = "PC]-0Bmp83h7F5#U!D6KJ(A&" - - #server_url = 'api.growsystem.muelleronline.org' - server_url = 'api.growsystem.muellerdev.kozow.com' - - wlan_ssid = 'Oppa-95.lan' - wlan_pw = '95%04-MM' - - sensors = [ - { - 'type': 'moisture', - 'pin_int': 26 - }, - { - 'type': 'ambilight', - 'pin_int': 8, # for compatibility only - 'pin_int_sda': 8, - 'pin_int_scl': 9 - }, - - - # { - # 'type': 'dht22', - # 'pin_int': 15 - # } - ] - - engines = [ - { - 'type': 'pump', - 'pins': [15] - } - ] - - read_secs = 5 - # Device Infos End - wlan = network.WLAN(network.STA_IF) + + app_version = "1.0.0" def get_macaddress(self): return self._format_mac(self.wlan.config('mac').hex()) @@ -54,13 +16,29 @@ class DeviceInfo: def get_all_device_infos(self): return { - 'name': self.name, + 'name': self.get_name(), 'mac_address': self.get_macaddress(), 'ip_address': self.get_ipaddress(), - 'token': self.token} + 'token': self.get_token()} - def config(self): - return self._loadConfig() + def config(self, filepath=None): + return self._loadJsonConfig(filepath) + + def app_config(self): + import gs.config.app as app_config + return app_config + + def server_url(self): + return self.app_config().api_url + + def get_token(self): + return self.config()['token'] if self.config() and self.config()['token'] else '' + + def get_name(self): + return self.config()['name'] if self.config() and self.config()['name'] else '' + + def get_device_id(self): + return self.config()['device_id'] if self.config() and self.config()['device_id'] else '' def _format_mac(self, mac): # Split the MAC address into pairs of two characters each @@ -69,10 +47,20 @@ class DeviceInfo: formatted_mac = ":".join(pairs) return formatted_mac - def _loadConfig(self): - with open('/gs/config/sensors.py', 'r') as file: + def _loadJsonConfig(self, filepath=None): + filepath = filepath if filepath else '/gs/config/device_config.json' + try: + file = open(filepath, "r") json_content = file.read() - return json.loads(json_content) + return json.loads(json_content) + except OSError: # open failed + print("File not found: ", filepath) + return None + + #with open(filepath, 'r') as file: + # json_content = file.read() + #return json.loads(json_content) + \ No newline at end of file diff --git a/gs/exceptions/not_subscriptable_error.py b/gs/exceptions/not_subscriptable_error.py new file mode 100644 index 0000000..19fa115 --- /dev/null +++ b/gs/exceptions/not_subscriptable_error.py @@ -0,0 +1,2 @@ +class NotSubscriptableError(Exception): + pass diff --git a/gs/grow_system_api.py b/gs/grow_system_api.py index fa7ab66..2c85799 100644 --- a/gs/grow_system_api.py +++ b/gs/grow_system_api.py @@ -14,7 +14,7 @@ class GrowSystemApi: base_url = '' def __init__(self): - self.base_url = self.device_info.server_url + self.base_url = self.device_info.server_url() self.connect_wifi(ic.config['ssid'], ic.config['password']) # config = self.device_info.config() @@ -22,6 +22,7 @@ class GrowSystemApi: # print("Test", config['test']) def activate(self, config): + print("ACtivate config:", config) data = self._get_device_data() data.update({ 'user_id': 1, @@ -29,6 +30,7 @@ class GrowSystemApi: }) print("activate ...", data) response = self.http_client.post(self.base_url + "/api/device/activate", data) + print("REsponse ...", response) return self._get_json_encoded(response.text) def say_hello(self): @@ -41,7 +43,13 @@ class GrowSystemApi: def send_measurements(self, device_id, data): url = self.base_url + "/api/device/" + str(device_id) + "/sensor-log" response = self.http_client.post(url, data) - return json.loads(response.text) + try: + return json.loads(response.text) + except ValueError as e: + print("JSON Value error raised after sending measurements") + except Exception as e: + print("Exception raised while sending measurements", e) + return response def _get_device_data(self): return self.device_info.get_all_device_infos() diff --git a/gs/growsystem.py b/gs/growsystem.py index 26885ad..6046be1 100644 --- a/gs/growsystem.py +++ b/gs/growsystem.py @@ -1,6 +1,13 @@ from gs.setup import Setup +from gs.device_info import DeviceInfo +from gs.sensor_data_manager import SensorDataManager import os import ujson +import machine +import time +from gs.classes.sensors.ambilight_sensor import AmbilightSensor +from gs.classes.sensors.dht22 import TemperatureHumiditySensor +from gs.classes.sensors.moisture_sensor import MoistureSensor class GrowSystem: @@ -9,6 +16,10 @@ class GrowSystem: initial_config = None + device_info = DeviceInfo() + + sensors = [] + def __init__(self): print("Initialize Growsystem", self.version) @@ -22,13 +33,37 @@ class GrowSystem: if self._is_config_existing(): print("Skip Setup. Config existing.") + self._initialize_sensors() elif self._is_initial_config_existing(): print("Initial config only existing (no base config). Start activation ...") self._activate() + + def start(self): + self.sensor_data_manager = SensorDataManager(self.device_info.get_device_id()) + + print("Start reading sensors ...") + + read_secs = self.device_info.app_config().read_secs + + while True: + # Reset data + self.most_recent_values = [] + + for sensor in self.sensors: + print("Read sensor of type " + sensor.type + " at pin " + str(sensor.sensor_pin_int)) + sensor.read() + for measurement in sensor.most_recent_values: + print(f"Got {measurement['value']} {measurement['unit']} ({measurement['type']})") + self.most_recent_values = self.most_recent_values + sensor.most_recent_values + + self.sensor_data_manager.handleData(self.most_recent_values) + + time.sleep(read_secs) def _setup(self): setup = Setup() setup.setup_pico() + machine.reset def _activate(self): print("Start activation!") @@ -36,16 +71,27 @@ class GrowSystem: self.initial_config = ic.config device_config = self.gsapi.activate(self.initial_config) #print("Device Config:", device_config['data']) - sensors = device_config['data']['sensors'] - sensor_configs = [] - for sensor in sensors: - sensor_configs.append(sensor['config']) - print(sensor['config']) - with open("/gs/config/device_config.py", "w") as f: - f.write("sensors = " + ujson.dumps(sensor_configs)) + + if True: + sensors = device_config['data']['sensors'] + sensor_configs = [] + for sensor in sensors: + sensor_configs.append(sensor['config']) + print(sensor['config']) + device_configs = { + 'name': device_config['data']['name'], + 'device_id': device_config['data']['id'], + 'token': device_config['data']['token'], + 'user_id': device_config['data']['user_id'], + 'sensors': sensor_configs + } + with open("/gs/config/device_config.json", "w") as f: + f.write(ujson.dumps(device_configs)) + if self._is_config_existing(): + machine.reset def _is_config_existing(self): - return self._is_file_existing('/gs/config/config.py') + return self._is_file_existing('/gs/config/device_config.json') def _is_initial_config_existing(self): return self._is_file_existing('/gs/config/initial_config.py') @@ -59,4 +105,25 @@ class GrowSystem: except OSError: # open failed # handle the file open cas return False + + def _initialize_sensors(self): + # Init sensors + sensors = self.device_info.config()['sensors'] + for sensor in sensors: + print("--------------------------------------") + print("Initialize sensor:") + print(sensor) + sensor_type = sensor['type'] + if sensor_type == 'moisture': + print("Found sensor of type moisture") + self.sensors.append(MoistureSensor(sensor)) + elif sensor_type == 'dht22': + print("Found sensor of type DHT22") + self.sensors.append(TemperatureHumiditySensor(sensor)) + elif sensor_type == 'ambilight': + print("Found sensor of type GY302/BH1750") + self.sensors.append(AmbilightSensor(sensor)) + else: + print("No sensor type configured for: " + sensor['type']) + diff --git a/gs/http_client.py b/gs/http_client.py index fd197ed..b819ff8 100644 --- a/gs/http_client.py +++ b/gs/http_client.py @@ -26,10 +26,11 @@ class HTTPClient: print("Send post request to: " + url) response = urequests.post(url, data=json_data, headers=headers) if response.status_code == 200: - return response + print("Request OK (200)") else: - print("Failed to send data. Status code:", response.status_code) - print(response.text) + print("Failed to send data.", response.status_code, response.text) + return response except Exception as e: - print("Exception occurred:", e) + print("Exception raised:", e) + return None diff --git a/gs/little_apache.py b/gs/little_apache.py index 841c96c..774a383 100644 --- a/gs/little_apache.py +++ b/gs/little_apache.py @@ -81,8 +81,9 @@ class LittleApache():

Setup Pico

SSID:
- Password:
- PIN:
+ Password:

+ ID:
+ PIN:
""" diff --git a/gs/sensor_data_manager.py b/gs/sensor_data_manager.py new file mode 100644 index 0000000..806870e --- /dev/null +++ b/gs/sensor_data_manager.py @@ -0,0 +1,24 @@ +from gs.grow_system_api import GrowSystemApi +# from device_info import DeviceInfo +from gs.exceptions.not_subscriptable_error import NotSubscriptableError + +class SensorDataManager: + + device_info = None + + grow_system_api = None + + device_id = None + + def __init__(self, device_id): + self.grow_system_api = GrowSystemApi() + # self.device_info = DeviceInfo() + self.device_id = device_id + + def handleData(self, data): + json_response = self.grow_system_api.send_measurements(self.device_id, data) + try: + print("Response message: " + json_response['message']) + except TypeError as e: + print("The response is no json data", e, json_response) + diff --git a/gs/setup.py b/gs/setup.py index 5b89e9d..fd5fea9 100644 --- a/gs/setup.py +++ b/gs/setup.py @@ -57,9 +57,10 @@ class Setup: config = { "ssid": config['ssid'], "password": config['password'], - "pin": config['pin'] + "pin": config['pin'], + "user_id": config['user_id'] } - print("Save config:", config) + print("Save initial config:", config) with open("/gs/config/initial_config.py", "w") as f: f.write("config = " + ujson.dumps(config)) diff --git a/lib/bh1750.py b/lib/bh1750.py new file mode 100644 index 0000000..e155a09 --- /dev/null +++ b/lib/bh1750.py @@ -0,0 +1,62 @@ +""" +Micropython BH1750 ambient light sensor driver. +* https://github.com/PinkInk/upylib/tree/master/bh1750 +""" + +from utime import sleep_ms + + +class BH1750(): + """Micropython BH1750 ambient light sensor driver.""" + + PWR_OFF = 0x00 + PWR_ON = 0x01 + RESET = 0x07 + + # modes + CONT_LOWRES = 0x13 + CONT_HIRES_1 = 0x10 + CONT_HIRES_2 = 0x11 + ONCE_HIRES_1 = 0x20 + ONCE_HIRES_2 = 0x21 + ONCE_LOWRES = 0x23 + + # default addr=0x23 if addr pin floating or pulled to ground + # addr=0x5c if addr pin pulled high + def __init__(self, bus, addr=0x23): + self.bus = bus + self.addr = addr + self.off() + self.reset() + + def off(self): + """Turn sensor off.""" + self.set_mode(self.PWR_OFF) + + def on(self): + """Turn sensor on.""" + self.set_mode(self.PWR_ON) + + def reset(self): + """Reset sensor, turn on first if required.""" + self.on() + self.set_mode(self.RESET) + + def set_mode(self, mode): + """Set sensor mode.""" + self.mode = mode + self.bus.writeto(self.addr, bytes([self.mode])) + + def luminance(self, mode): + """Sample luminance (in lux), using specified sensor mode.""" + # continuous modes + if mode & 0x10 and mode != self.mode: + self.set_mode(mode) + # one shot modes + if mode & 0x20: + self.set_mode(mode) + # earlier measurements return previous reading + sleep_ms(24 if mode in (0x13, 0x23) else 180) + data = self.bus.readfrom(self.addr, 2) + factor = 2.0 if mode in (0x11, 0x21) else 1.0 + return (data[0]<<8 | data[1]) / (1.2 * factor) diff --git a/main.py b/main.py index 71b2e28..ae2ca15 100644 --- a/main.py +++ b/main.py @@ -5,8 +5,9 @@ from time import sleep if __name__ == '__main__': gs = GrowSystem() + gs.start() while True: print("Keep running in main.py") sleep(5) - + \ No newline at end of file -- 2.40.1 From 9397fcd8b833122989a58750fad533422c51c934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Mu=CC=88ller?= Date: Tue, 7 May 2024 13:25:42 +0200 Subject: [PATCH 13/13] final for release --- classes/http_request.py | 72 ----------- config/app.py | 1 - dev_pi_pico_2405041205/ambilight_sensor.py | 34 ----- dev_pi_pico_2405041205/bh1750.py | 62 --------- dev_pi_pico_2405041205/device_info.py | 69 ---------- dev_pi_pico_2405041205/dht22.py | 36 ------ dev_pi_pico_2405041205/engine.py | 23 ---- dev_pi_pico_2405041205/grow_system.py | 96 -------------- dev_pi_pico_2405041205/grow_system_api.py | 31 ----- dev_pi_pico_2405041205/http_client.py | 35 ------ dev_pi_pico_2405041205/main.py | 57 --------- dev_pi_pico_2405041205/moisture_sensor.py | 39 ------ dev_pi_pico_2405041205/pump.py | 7 -- dev_pi_pico_2405041205/sensor_data_manager.py | 20 --- dev_pi_pico_2405041205/sensors.py | 13 -- dev_pi_pico_2405041205/wlan.py | 39 ------ gs/config/{ => examples}/device_config.json | 0 gs/config/{ => examples}/initial_config.py | 0 old_version/README.md | 2 - old_version/REDME.md | 3 - old_version/ambilight_sensor.py | 34 ----- old_version/bh1750.old_1/__init__.py | 1 - old_version/bh1750.old_1/bh1750.py | 118 ------------------ old_version/device_info.py | 69 ---------- old_version/dht22.py | 36 ------ old_version/engine.py | 23 ---- old_version/grow_system.py | 96 -------------- old_version/grow_system_api.py | 38 ------ old_version/http_client.py | 35 ------ old_version/lib/bh1750.py | 62 --------- old_version/main.py | 63 ---------- old_version/moisture_sensor.py | 39 ------ .../notes/code_sample_moisture_sensor.txt | 31 ----- old_version/pump.py | 7 -- old_version/sensor_data_manager.py | 20 --- old_version/sensors.py | 13 -- old_version/setup.py | 113 ----------------- old_version/wlan.py | 39 ------ teststuff/main.py | 50 -------- 39 files changed, 1526 deletions(-) delete mode 100644 classes/http_request.py delete mode 100644 config/app.py delete mode 100644 dev_pi_pico_2405041205/ambilight_sensor.py delete mode 100644 dev_pi_pico_2405041205/bh1750.py delete mode 100644 dev_pi_pico_2405041205/device_info.py delete mode 100644 dev_pi_pico_2405041205/dht22.py delete mode 100644 dev_pi_pico_2405041205/engine.py delete mode 100644 dev_pi_pico_2405041205/grow_system.py delete mode 100644 dev_pi_pico_2405041205/grow_system_api.py delete mode 100644 dev_pi_pico_2405041205/http_client.py delete mode 100644 dev_pi_pico_2405041205/main.py delete mode 100644 dev_pi_pico_2405041205/moisture_sensor.py delete mode 100644 dev_pi_pico_2405041205/pump.py delete mode 100644 dev_pi_pico_2405041205/sensor_data_manager.py delete mode 100644 dev_pi_pico_2405041205/sensors.py delete mode 100644 dev_pi_pico_2405041205/wlan.py rename gs/config/{ => examples}/device_config.json (100%) rename gs/config/{ => examples}/initial_config.py (100%) delete mode 100644 old_version/README.md delete mode 100644 old_version/REDME.md delete mode 100644 old_version/ambilight_sensor.py delete mode 100644 old_version/bh1750.old_1/__init__.py delete mode 100644 old_version/bh1750.old_1/bh1750.py delete mode 100644 old_version/device_info.py delete mode 100644 old_version/dht22.py delete mode 100644 old_version/engine.py delete mode 100644 old_version/grow_system.py delete mode 100644 old_version/grow_system_api.py delete mode 100644 old_version/http_client.py delete mode 100644 old_version/lib/bh1750.py delete mode 100644 old_version/main.py delete mode 100644 old_version/moisture_sensor.py delete mode 100644 old_version/notes/code_sample_moisture_sensor.txt delete mode 100644 old_version/pump.py delete mode 100644 old_version/sensor_data_manager.py delete mode 100644 old_version/sensors.py delete mode 100644 old_version/setup.py delete mode 100644 old_version/wlan.py delete mode 100644 teststuff/main.py diff --git a/classes/http_request.py b/classes/http_request.py deleted file mode 100644 index c85063c..0000000 --- a/classes/http_request.py +++ /dev/null @@ -1,72 +0,0 @@ -import json -import ure as re - - -class HttpRequest: - - METHOD = { - "GET": "GET", - "POST": "POST" - } - - method = '' - path = '' - raw_content = '' - headers = {} - - def __init__(self, request): - self.original_request = request - # self.method = method - # self.path = path - # self.headers = headers - # self.raw_content = content - print("http request initialized") - self.parse_request(request) - - def parse_request(self, request): - # Split the request into lines - lines = request.decode().split('\r\n') - - # Extract method, path, and HTTP version from the first line - self.method, self.path, _ = lines[0].split() - - # Parse headers - for line in lines[1:]: - if not line: - break # Empty line indicates end of headers - key, value = line.split(': ', 1) - self.headers[key] = value - - # Content is assumed to be in the last line - self.raw_content = lines[-1] - - def get_content_json(self): - # Parse the POST request content into a dictionary - parsed_content = {} - pairs = self.raw_content.split('&') - for pair in pairs: - key, value = pair.split('=') - parsed_content[key] = value - - # Encode the values in the dictionary - encoded_content = {} - for key, value in parsed_content.items(): - encoded_value = re.sub(r'%([0-9A-Fa-f]{2})', lambda m: chr(int(m.group(1), 16)), value) - encoded_content[key] = encoded_value - - return encoded_content - - def __str__(self): - return { - "method": self.method, - "headers": self.headers, - "content": self.raw_content, - "content_json": self.get_content_json() - } - - - - - - - diff --git a/config/app.py b/config/app.py deleted file mode 100644 index 8a5b5e3..0000000 --- a/config/app.py +++ /dev/null @@ -1 +0,0 @@ -api_url = 'https://growsystem.muellerdev.kozow.com/api/' diff --git a/dev_pi_pico_2405041205/ambilight_sensor.py b/dev_pi_pico_2405041205/ambilight_sensor.py deleted file mode 100644 index c8f0a3c..0000000 --- a/dev_pi_pico_2405041205/ambilight_sensor.py +++ /dev/null @@ -1,34 +0,0 @@ -from sensors import Sensors -from machine import Pin, I2C -from utime import sleep -from lib.bh1750 import BH1750 - - -class AmbilightSensor(Sensors): - - - most_recent_values = [] - - def __init__(self, settings): - super().__init__(settings) - print(settings) # TODO remove - self.sensor_pin_int = settings['pin_int'] - # self.sensor = DHT22(Pin(self.sensor_pin_int, Pin.IN, Pin.PULL_UP)) - self.sensor = BH1750(I2C(0, sda=Pin(settings['pin_int_sda']), scl=Pin(settings['pin_int_scl']))) - - def read(self): - try: - measurement = self.sensor.luminance(BH1750.ONCE_HIRES_1) - print("ambilight ..") - print(measurement) - self.most_recent_values = [ - { - 'type': 'ambilight', - 'value': measurement, - 'unit': '-' - }, - ] - except OSError: - print('Ambilight Error reading temperature/humidity. Check wires') - print() - diff --git a/dev_pi_pico_2405041205/bh1750.py b/dev_pi_pico_2405041205/bh1750.py deleted file mode 100644 index 0f91b49..0000000 --- a/dev_pi_pico_2405041205/bh1750.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Micropython BH1750 ambient light sensor driver. -* https://github.com/PinkInk/upylib/tree/master/bh1750 -""" - -from utime import sleep_ms - - -class BH1750(): - """Micropython BH1750 ambient light sensor driver.""" - - PWR_OFF = 0x00 - PWR_ON = 0x01 - RESET = 0x07 - - # modes - CONT_LOWRES = 0x13 - CONT_HIRES_1 = 0x10 - CONT_HIRES_2 = 0x11 - ONCE_HIRES_1 = 0x20 - ONCE_HIRES_2 = 0x21 - ONCE_LOWRES = 0x23 - - # default addr=0x23 if addr pin floating or pulled to ground - # addr=0x5c if addr pin pulled high - def __init__(self, bus, addr=0x23): - self.bus = bus - self.addr = addr - self.off() - self.reset() - - def off(self): - """Turn sensor off.""" - self.set_mode(self.PWR_OFF) - - def on(self): - """Turn sensor on.""" - self.set_mode(self.PWR_ON) - - def reset(self): - """Reset sensor, turn on first if required.""" - self.on() - self.set_mode(self.RESET) - - def set_mode(self, mode): - """Set sensor mode.""" - self.mode = mode - self.bus.writeto(self.addr, bytes([self.mode])) - - def luminance(self, mode): - """Sample luminance (in lux), using specified sensor mode.""" - # continuous modes - if mode & 0x10 and mode != self.mode: - self.set_mode(mode) - # one shot modes - if mode & 0x20: - self.set_mode(mode) - # earlier measurements return previous reading - sleep_ms(24 if mode in (0x13, 0x23) else 180) - data = self.bus.readfrom(self.addr, 2) - factor = 2.0 if mode in (0x11, 0x21) else 1.0 - return (data[0]<<8 | data[1]) / (1.2 * factor) \ No newline at end of file diff --git a/dev_pi_pico_2405041205/device_info.py b/dev_pi_pico_2405041205/device_info.py deleted file mode 100644 index a61681e..0000000 --- a/dev_pi_pico_2405041205/device_info.py +++ /dev/null @@ -1,69 +0,0 @@ -import network - - -class DeviceInfo: - - # Device Infos - name = "Dev Device 1" - - token = "PC]-0Bmp83h7F5#U!D6KJ(A&" - - server_url = 'api.growsystem.muelleronline.org' - - wlan_ssid = 'Oppa-95.lan' - wlan_pw = '95%04-MM' - - sensors = [ - { - 'type': 'moisture', - 'pin_int': 26 - }, - { - 'type': 'ambilight', - 'pin_int': 8, # for compatibility only - 'pin_int_sda': 8, - 'pin_int_scl': 9 - }, - - - # { - # 'type': 'dht22', - # 'pin_int': 15 - # } - ] - - engines = [ - { - 'type': 'pump', - 'pins': [15] - } - ] - - read_secs = 5 - # Device Infos End - - wlan = network.WLAN(network.STA_IF) - - def get_macaddress(self): - return self._format_mac(self.wlan.config('mac').hex()) - - def get_ipaddress(self): - return self.wlan.ifconfig()[0] - - def get_all_device_infos(self): - return { - 'name': self.name, - 'mac_address': self.get_macaddress(), - 'ip_address': self.get_ipaddress(), - 'token': self.token} - - def _format_mac(self, mac): - # Split the MAC address into pairs of two characters each - pairs = [mac[i:i+2] for i in range(0, len(mac), 2)] - # Join the pairs with colons to create the formatted MAC address - formatted_mac = ":".join(pairs) - return formatted_mac - - - - \ No newline at end of file diff --git a/dev_pi_pico_2405041205/dht22.py b/dev_pi_pico_2405041205/dht22.py deleted file mode 100644 index c022666..0000000 --- a/dev_pi_pico_2405041205/dht22.py +++ /dev/null @@ -1,36 +0,0 @@ -from sensors import Sensors -from dht import DHT22 -from machine import ADC, Pin - - -class TemperatureHumiditySensor(Sensors): - - sensor = None - - most_recent_values = [] - - def __init__(self, settings): - super().__init__(settings) - print("Initialize dht22 sensor. Sensor pin is: " + str(settings['pin_int'])) - print(settings) - self.sensor_pin_int = settings['pin_int'] - self.sensor = DHT22(Pin(self.sensor_pin_int, Pin.IN, Pin.PULL_UP)) - - def read(self): - try: - self.sensor.measure() - self.most_recent_values = [ - { - 'type': 'temperature', - 'value': self.sensor.temperature(), - 'unit': 'C' - }, - { - 'type': 'humidity', - 'value': self.sensor.humidity(), - 'unit': '%' - } - ] - except OSError: - print('DHT22 Error reading temperature/humidity. Check wires') - print() diff --git a/dev_pi_pico_2405041205/engine.py b/dev_pi_pico_2405041205/engine.py deleted file mode 100644 index 38bf29c..0000000 --- a/dev_pi_pico_2405041205/engine.py +++ /dev/null @@ -1,23 +0,0 @@ -from machine import Pin - - -class Engine(): - - pins = [] - - engine = None - - def __init__(self, engine): - print("Hello from Engine parent class") - print(engine) - self.pins = engine['pins'] - self.engine = Pin(self.pins[0], Pin.OUT) - - def on(self): - print("engine on") - self.engine.value(1) - - def off(self): - print("engine off") - self.engine.value(0) - diff --git a/dev_pi_pico_2405041205/grow_system.py b/dev_pi_pico_2405041205/grow_system.py deleted file mode 100644 index 3861c5a..0000000 --- a/dev_pi_pico_2405041205/grow_system.py +++ /dev/null @@ -1,96 +0,0 @@ -import time -from moisture_sensor import MoistureSensor -from dht22 import TemperatureHumiditySensor -from ambilight_sensor import AmbilightSensor -from pump import Pump -from sensor_data_manager import SensorDataManager -from grow_system_api import GrowSystemApi -from device_info import DeviceInfo - - -class GrowSystem: - - grow_system_api = GrowSystemApi() - - # moisture_sensor = None - # temperature_humidity_sensor = None - - sensors = [] - - engines = [] - - most_recent_values = [] - - sensor_data_manager = None - - device_id = None - - device_info = DeviceInfo() - - def __init__(self, settings): - # Init sensors - for sensor in self.device_info.sensors: - print("") - print("Initialize sensor:") - print(sensor) - sensor_type = sensor['type'] - if sensor_type == 'moisture': - print("Found sensor of type moisture") - self.sensors.append(MoistureSensor(sensor)) - elif sensor_type == 'dht22': - print("Found sensor of type DHT22") - self.sensors.append(TemperatureHumiditySensor(sensor)) - elif sensor_type == 'ambilight': - print("Found sensor of type GY302/BH1750") - self.sensors.append(AmbilightSensor(sensor)) - else: - print("No sensor type configured for: " + sensor['type']) - - # Init engines - for engine in self.device_info.engines: - print("") - print("Initialize engine:") - print(engine) - engine_type = engine['type'] - if engine_type == 'pump': - print("Found egine of type pump") - self.engines.append(Pump(engine)) - self.engines[0].on() - time.sleep(15) - self.engines[0].off() - - - #if not self.moisture_sensor: - # self.moisture_sensor = MoistureSensor(settings['moisture_sensor']) - - #if not self.temperature_humidity_sensor: - # self.temperature_humidity_sensor = TemperatureHumiditySensor(settings['temperature_humidity_sensor']) - - def start(self): - print("Say the server hello...") - result = self.grow_system_api.say_hello() - message = result['message'] - - if message != 'OK': - print("Device not activated. Stopping") - return - - self.device_id = result['data']['device_id'] - self.sensor_data_manager = SensorDataManager(self.device_id) - - print("Start reading sensors ...") - while True: - # Reset data - self.most_recent_values = [] - - for sensor in self.sensors: - print("Read sensor of type " + sensor.type + " at pin " + str(sensor.sensor_pin_int)) - sensor.read() - for measurement in sensor.most_recent_values: - print(f"Got {measurement['value']} {measurement['unit']} ({measurement['type']})") - self.most_recent_values = self.most_recent_values + sensor.most_recent_values - - self.sensor_data_manager.handleData(self.most_recent_values) - - time.sleep(self.device_info.read_secs) - diff --git a/dev_pi_pico_2405041205/grow_system_api.py b/dev_pi_pico_2405041205/grow_system_api.py deleted file mode 100644 index 0e3376c..0000000 --- a/dev_pi_pico_2405041205/grow_system_api.py +++ /dev/null @@ -1,31 +0,0 @@ -from http_client import HTTPClient -from device_info import DeviceInfo -import json - - -class GrowSystemApi: - - http_client = HTTPClient() - - device_info = DeviceInfo() - - base_url = '' - - def __init__(self): - self.base_url = self.device_info.server_url - - def say_hello(self): - response = self.http_client.post(self.base_url + "/api/device", self._get_device_data()) - print(response.text) - jsonResult = json.loads(response.text) - print(jsonResult) - return jsonResult; - - def send_measurements(self, device_id, data): - url = self.base_url + "/api/device/" + str(device_id) + "/sensor-log" - response = self.http_client.post(url, data) - return json.loads(response.text) - - def _get_device_data(self): - return self.device_info.get_all_device_infos() - diff --git a/dev_pi_pico_2405041205/http_client.py b/dev_pi_pico_2405041205/http_client.py deleted file mode 100644 index fd197ed..0000000 --- a/dev_pi_pico_2405041205/http_client.py +++ /dev/null @@ -1,35 +0,0 @@ -import urequests -import json - -class HTTPClient: - def __init__(self): - pass - - def get(self, url): - url = 'https://' + url - try: - # headers = {'Content-Type': 'application/json'} - response = urequests.get(url) - if response.status_code == 200: - print("Data sent, got response") - return response - else: - print("Failed to get data. Status code:", response.status_code) - except Exception as e: - print("Exception occurred:", e) - - def post(self, url, data): - url = 'https://' + url - try: - headers = {'Content-Type': 'application/json', 'Accept': 'application/json, text/plain, */*'} - json_data = json.dumps(data) - print("Send post request to: " + url) - response = urequests.post(url, data=json_data, headers=headers) - if response.status_code == 200: - return response - else: - print("Failed to send data. Status code:", response.status_code) - print(response.text) - except Exception as e: - print("Exception occurred:", e) - diff --git a/dev_pi_pico_2405041205/main.py b/dev_pi_pico_2405041205/main.py deleted file mode 100644 index 964a84b..0000000 --- a/dev_pi_pico_2405041205/main.py +++ /dev/null @@ -1,57 +0,0 @@ -# GrowSystem -# Author: Maik Müller (maik@muelleronlineorg) - -# WIP! -# This file should do only: -# - provide constants for settings -# - eventually necessary system settings -# - init wlan connection -# - Call base class, permitting the configured constants -import network -import urequests -from grow_system import GrowSystem -from wlan import WlanClient -from http_client import HTTPClient -from device_info import DeviceInfo - - -settings = { - 'wlan_ssid': 'Oppa-95.lan', - 'wlan_pw': '95%04-MM', - 'moisture_sensor': { - 'pin_int': 26 - }, - 'temperature_humidity_sensor': { - 'pin_int': 15 - }, - 'pump_pin_int': 24 -} - - -def wlan_scan(): - # Client-Betrieb - wlan = network.WLAN(network.STA_IF) - # WLAN-Interface aktivieren - wlan.active(True) - # WLANs ausgeben - found_wlans = wlan.scan() - return found_wlans - - -# Press the green button in the gutter to run the script. -if __name__ == '__main__': - #print(wlan_scan()) - print("Connect WLAN") - wlanClient = WlanClient(settings['wlan_ssid'], settings['wlan_pw']) - wlanClient.connect() - print("") - - di = DeviceInfo() - print("Device Infos:") - print(di.get_all_device_infos()) - print("") - - print("Start grow system") - gs = GrowSystem(settings) - gs.start() - diff --git a/dev_pi_pico_2405041205/moisture_sensor.py b/dev_pi_pico_2405041205/moisture_sensor.py deleted file mode 100644 index e11ca76..0000000 --- a/dev_pi_pico_2405041205/moisture_sensor.py +++ /dev/null @@ -1,39 +0,0 @@ -# Moisture Sensor Class -from sensors import Sensors -from machine import ADC, Pin - - -class MoistureSensor(Sensors): - - sensor = None - - most_recent_values = [] - - min_raw_value = None - max_raw_value = None - - def __init__(self, sensor_data, min_raw_value=300, max_raw_value=65535): - super().__init__(sensor_data) - print("Initialize moisture sensor. Sensor pin is: " + str(sensor_data['pin_int'])) - self.sensor_pin_int = sensor_data['pin_int'] - self.min_raw_value = min_raw_value - self.max_raw_value = max_raw_value - self.sensor = ADC(Pin(self.sensor_pin_int)) - - def read(self): - self.most_recent_values = [ - { - 'type': 'moisture', - 'value': self.convert_to_moisture_percentage(self.sensor.read_u16()), - 'unit': '%' - }, - ] - - def normalize_sensor_value(self, raw_value): - return (raw_value - self.min_raw_value) / (self.max_raw_value - self.min_raw_value) - - def convert_to_moisture_percentage(self, raw_value): - normalized_value = self.normalize_sensor_value(raw_value) - return round(100 - normalized_value * 100, 1) - - \ No newline at end of file diff --git a/dev_pi_pico_2405041205/pump.py b/dev_pi_pico_2405041205/pump.py deleted file mode 100644 index fc39e6d..0000000 --- a/dev_pi_pico_2405041205/pump.py +++ /dev/null @@ -1,7 +0,0 @@ -from engine import Engine - - -class Pump(Engine): - - def __init__(self, engine): - super().__init__(engine) diff --git a/dev_pi_pico_2405041205/sensor_data_manager.py b/dev_pi_pico_2405041205/sensor_data_manager.py deleted file mode 100644 index 87dbf39..0000000 --- a/dev_pi_pico_2405041205/sensor_data_manager.py +++ /dev/null @@ -1,20 +0,0 @@ -from grow_system_api import GrowSystemApi -# from device_info import DeviceInfo - - -class SensorDataManager: - - device_info = None - - grow_system_api = None - - device_id = None - - def __init__(self, device_id): - self.grow_system_api = GrowSystemApi() - # self.device_info = DeviceInfo() - self.device_id = device_id - - def handleData(self, data): - jsonResponse = self.grow_system_api.send_measurements(self.device_id, data) - print("Response message: " + jsonResponse['message']) \ No newline at end of file diff --git a/dev_pi_pico_2405041205/sensors.py b/dev_pi_pico_2405041205/sensors.py deleted file mode 100644 index 23ad803..0000000 --- a/dev_pi_pico_2405041205/sensors.py +++ /dev/null @@ -1,13 +0,0 @@ -class Sensors: - # this is a parent class for the Sensor classes - sensor_pin_int = -1 - - sensor = None - - type = "unset" - - def __init__(self, settings): - self.type = settings['type'] - print("Initialize " + self.type + " sensor. Sensor pin is: " + str(settings['pin_int'])) - - \ No newline at end of file diff --git a/dev_pi_pico_2405041205/wlan.py b/dev_pi_pico_2405041205/wlan.py deleted file mode 100644 index c265d8e..0000000 --- a/dev_pi_pico_2405041205/wlan.py +++ /dev/null @@ -1,39 +0,0 @@ -import machine -import network -import time -# network.country('DE') - - -class WlanClient: - - ssid = '' - pw = '' - wlan = None - # Status-LED - led_onboard = machine.Pin('LED', machine.Pin.OUT) - led_onboard.value(False) - - def __init__(self, ssid, pw): - # print("Hello from wlan class") - self.ssid = ssid - self.pw = pw - self.wlan = network.WLAN(network.STA_IF) - - def connect(self): - if not self.is_connected(): - print('No WLAN connected. Connecting ...' + self.ssid + ' ' + self.pw) - self.wlan.active(True) - self.wlan.connect(self.ssid, self.pw) - for i in range(10): - if self.wlan.status() < 0 or self.wlan.status() >= 3: - break - time.sleep(1) - # led_value = self.led_onboard.value() == 1 - # self.led_onboard.value(led_value) - if self.wlan.isconnected(): - net_config = self.wlan.ifconfig() - print("NetConfig:") - print(net_config) - - def is_connected(self): - return self.wlan.isconnected() diff --git a/gs/config/device_config.json b/gs/config/examples/device_config.json similarity index 100% rename from gs/config/device_config.json rename to gs/config/examples/device_config.json diff --git a/gs/config/initial_config.py b/gs/config/examples/initial_config.py similarity index 100% rename from gs/config/initial_config.py rename to gs/config/examples/initial_config.py diff --git a/old_version/README.md b/old_version/README.md deleted file mode 100644 index f90de4d..0000000 --- a/old_version/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# GrowSystem - diff --git a/old_version/REDME.md b/old_version/REDME.md deleted file mode 100644 index bc52edf..0000000 --- a/old_version/REDME.md +++ /dev/null @@ -1,3 +0,0 @@ -# Show output on terminal # -`minicom -b 115200 -o -D /dev/cu.usbmodem3301` - diff --git a/old_version/ambilight_sensor.py b/old_version/ambilight_sensor.py deleted file mode 100644 index c8f0a3c..0000000 --- a/old_version/ambilight_sensor.py +++ /dev/null @@ -1,34 +0,0 @@ -from sensors import Sensors -from machine import Pin, I2C -from utime import sleep -from lib.bh1750 import BH1750 - - -class AmbilightSensor(Sensors): - - - most_recent_values = [] - - def __init__(self, settings): - super().__init__(settings) - print(settings) # TODO remove - self.sensor_pin_int = settings['pin_int'] - # self.sensor = DHT22(Pin(self.sensor_pin_int, Pin.IN, Pin.PULL_UP)) - self.sensor = BH1750(I2C(0, sda=Pin(settings['pin_int_sda']), scl=Pin(settings['pin_int_scl']))) - - def read(self): - try: - measurement = self.sensor.luminance(BH1750.ONCE_HIRES_1) - print("ambilight ..") - print(measurement) - self.most_recent_values = [ - { - 'type': 'ambilight', - 'value': measurement, - 'unit': '-' - }, - ] - except OSError: - print('Ambilight Error reading temperature/humidity. Check wires') - print() - diff --git a/old_version/bh1750.old_1/__init__.py b/old_version/bh1750.old_1/__init__.py deleted file mode 100644 index ab5e217..0000000 --- a/old_version/bh1750.old_1/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .bh1750 import BH1750 diff --git a/old_version/bh1750.old_1/bh1750.py b/old_version/bh1750.old_1/bh1750.py deleted file mode 100644 index 21cebbe..0000000 --- a/old_version/bh1750.old_1/bh1750.py +++ /dev/null @@ -1,118 +0,0 @@ -# https://github.com/flrrth/pico-bh1750 - -import math - -from micropython import const -from utime import sleep_ms - - -class BH1750: - """Class for the BH1750 digital Ambient Light Sensor - - The datasheet can be found at https://components101.com/sites/default/files/component_datasheet/BH1750.pdf - """ - - MEASUREMENT_MODE_CONTINUOUSLY = const(1) - MEASUREMENT_MODE_ONE_TIME = const(2) - - RESOLUTION_HIGH = const(0) - RESOLUTION_HIGH_2 = const(1) - RESOLUTION_LOW = const(2) - - MEASUREMENT_TIME_DEFAULT = const(69) - MEASUREMENT_TIME_MIN = const(31) - MEASUREMENT_TIME_MAX = const(254) - - def __init__(self, address, i2c): - self._address = address - self._i2c = i2c - self._measurement_mode = BH1750.MEASUREMENT_MODE_ONE_TIME - self._resolution = BH1750.RESOLUTION_HIGH - self._measurement_time = BH1750.MEASUREMENT_TIME_DEFAULT - - self._write_measurement_time() - self._write_measurement_mode() - - def configure(self, measurement_mode: int, resolution: int, measurement_time: int): - """Configures the BH1750. - - Keyword arguments: - measurement_mode -- measure either continuously or once - resolution -- return measurements in either high, high2 or low resolution - measurement_time -- the duration of a single measurement - """ - if measurement_time not in range(BH1750.MEASUREMENT_TIME_MIN, BH1750.MEASUREMENT_TIME_MAX + 1): - raise ValueError("measurement_time must be between {0} and {1}" - .format(BH1750.MEASUREMENT_TIME_MIN, BH1750.MEASUREMENT_TIME_MAX)) - - self._measurement_mode = measurement_mode - self._resolution = resolution - self._measurement_time = measurement_time - - self._write_measurement_time() - self._write_measurement_mode() - - def _write_measurement_time(self): - buffer = bytearray(1) - - high_bit = 1 << 6 | self._measurement_time >> 5 - low_bit = 3 << 5 | (self._measurement_time << 3) >> 3 - - buffer[0] = high_bit - self._i2c.writeto(self._address, buffer) - - buffer[0] = low_bit - self._i2c.writeto(self._address, buffer) - - def _write_measurement_mode(self): - buffer = bytearray(1) - - buffer[0] = self._measurement_mode << 4 | self._resolution - self._i2c.writeto(self._address, buffer) - sleep_ms(24 if self._measurement_time == BH1750.RESOLUTION_LOW else 180) - - def reset(self): - """Clear the illuminance data register.""" - self._i2c.writeto(self._address, bytearray(b'\x07')) - - def power_on(self): - """Powers on the BH1750.""" - self._i2c.writeto(self._address, bytearray(b'\x01')) - - def power_off(self): - """Powers off the BH1750.""" - self._i2c.writeto(self._address, bytearray(b'\x00')) - - @property - def measurement(self) -> float: - """Returns the latest measurement.""" - if self._measurement_mode == BH1750.MEASUREMENT_MODE_ONE_TIME: - self._write_measurement_mode() - - buffer = bytearray(2) - self._i2c.readfrom_into(self._address, buffer) - lux = (buffer[0] << 8 | buffer[1]) / (1.2 * (BH1750.MEASUREMENT_TIME_DEFAULT / self._measurement_time)) - - if self._resolution == BH1750.RESOLUTION_HIGH_2: - return lux / 2 - else: - return lux - - def measurements(self) -> float: - """This is a generator function that continues to provide the latest measurement. Because the measurement time - is greatly affected by resolution and the configured measurement time, this function attemts to calculate the - appropriate sleep time between measurements. - - Example usage: - - for measurement in bh1750.measurements(): # bh1750 is an instance of this class - print(measurement) - """ - while True: - yield self.measurement - - if self._measurement_mode == BH1750.MEASUREMENT_MODE_CONTINUOUSLY: - base_measurement_time = 16 if self._measurement_time == BH1750.RESOLUTION_LOW else 120 - sleep_ms(math.ceil(base_measurement_time * self._measurement_time / BH1750.MEASUREMENT_TIME_DEFAULT)) - - diff --git a/old_version/device_info.py b/old_version/device_info.py deleted file mode 100644 index a61681e..0000000 --- a/old_version/device_info.py +++ /dev/null @@ -1,69 +0,0 @@ -import network - - -class DeviceInfo: - - # Device Infos - name = "Dev Device 1" - - token = "PC]-0Bmp83h7F5#U!D6KJ(A&" - - server_url = 'api.growsystem.muelleronline.org' - - wlan_ssid = 'Oppa-95.lan' - wlan_pw = '95%04-MM' - - sensors = [ - { - 'type': 'moisture', - 'pin_int': 26 - }, - { - 'type': 'ambilight', - 'pin_int': 8, # for compatibility only - 'pin_int_sda': 8, - 'pin_int_scl': 9 - }, - - - # { - # 'type': 'dht22', - # 'pin_int': 15 - # } - ] - - engines = [ - { - 'type': 'pump', - 'pins': [15] - } - ] - - read_secs = 5 - # Device Infos End - - wlan = network.WLAN(network.STA_IF) - - def get_macaddress(self): - return self._format_mac(self.wlan.config('mac').hex()) - - def get_ipaddress(self): - return self.wlan.ifconfig()[0] - - def get_all_device_infos(self): - return { - 'name': self.name, - 'mac_address': self.get_macaddress(), - 'ip_address': self.get_ipaddress(), - 'token': self.token} - - def _format_mac(self, mac): - # Split the MAC address into pairs of two characters each - pairs = [mac[i:i+2] for i in range(0, len(mac), 2)] - # Join the pairs with colons to create the formatted MAC address - formatted_mac = ":".join(pairs) - return formatted_mac - - - - \ No newline at end of file diff --git a/old_version/dht22.py b/old_version/dht22.py deleted file mode 100644 index c022666..0000000 --- a/old_version/dht22.py +++ /dev/null @@ -1,36 +0,0 @@ -from sensors import Sensors -from dht import DHT22 -from machine import ADC, Pin - - -class TemperatureHumiditySensor(Sensors): - - sensor = None - - most_recent_values = [] - - def __init__(self, settings): - super().__init__(settings) - print("Initialize dht22 sensor. Sensor pin is: " + str(settings['pin_int'])) - print(settings) - self.sensor_pin_int = settings['pin_int'] - self.sensor = DHT22(Pin(self.sensor_pin_int, Pin.IN, Pin.PULL_UP)) - - def read(self): - try: - self.sensor.measure() - self.most_recent_values = [ - { - 'type': 'temperature', - 'value': self.sensor.temperature(), - 'unit': 'C' - }, - { - 'type': 'humidity', - 'value': self.sensor.humidity(), - 'unit': '%' - } - ] - except OSError: - print('DHT22 Error reading temperature/humidity. Check wires') - print() diff --git a/old_version/engine.py b/old_version/engine.py deleted file mode 100644 index 38bf29c..0000000 --- a/old_version/engine.py +++ /dev/null @@ -1,23 +0,0 @@ -from machine import Pin - - -class Engine(): - - pins = [] - - engine = None - - def __init__(self, engine): - print("Hello from Engine parent class") - print(engine) - self.pins = engine['pins'] - self.engine = Pin(self.pins[0], Pin.OUT) - - def on(self): - print("engine on") - self.engine.value(1) - - def off(self): - print("engine off") - self.engine.value(0) - diff --git a/old_version/grow_system.py b/old_version/grow_system.py deleted file mode 100644 index 3861c5a..0000000 --- a/old_version/grow_system.py +++ /dev/null @@ -1,96 +0,0 @@ -import time -from moisture_sensor import MoistureSensor -from dht22 import TemperatureHumiditySensor -from ambilight_sensor import AmbilightSensor -from pump import Pump -from sensor_data_manager import SensorDataManager -from grow_system_api import GrowSystemApi -from device_info import DeviceInfo - - -class GrowSystem: - - grow_system_api = GrowSystemApi() - - # moisture_sensor = None - # temperature_humidity_sensor = None - - sensors = [] - - engines = [] - - most_recent_values = [] - - sensor_data_manager = None - - device_id = None - - device_info = DeviceInfo() - - def __init__(self, settings): - # Init sensors - for sensor in self.device_info.sensors: - print("") - print("Initialize sensor:") - print(sensor) - sensor_type = sensor['type'] - if sensor_type == 'moisture': - print("Found sensor of type moisture") - self.sensors.append(MoistureSensor(sensor)) - elif sensor_type == 'dht22': - print("Found sensor of type DHT22") - self.sensors.append(TemperatureHumiditySensor(sensor)) - elif sensor_type == 'ambilight': - print("Found sensor of type GY302/BH1750") - self.sensors.append(AmbilightSensor(sensor)) - else: - print("No sensor type configured for: " + sensor['type']) - - # Init engines - for engine in self.device_info.engines: - print("") - print("Initialize engine:") - print(engine) - engine_type = engine['type'] - if engine_type == 'pump': - print("Found egine of type pump") - self.engines.append(Pump(engine)) - self.engines[0].on() - time.sleep(15) - self.engines[0].off() - - - #if not self.moisture_sensor: - # self.moisture_sensor = MoistureSensor(settings['moisture_sensor']) - - #if not self.temperature_humidity_sensor: - # self.temperature_humidity_sensor = TemperatureHumiditySensor(settings['temperature_humidity_sensor']) - - def start(self): - print("Say the server hello...") - result = self.grow_system_api.say_hello() - message = result['message'] - - if message != 'OK': - print("Device not activated. Stopping") - return - - self.device_id = result['data']['device_id'] - self.sensor_data_manager = SensorDataManager(self.device_id) - - print("Start reading sensors ...") - while True: - # Reset data - self.most_recent_values = [] - - for sensor in self.sensors: - print("Read sensor of type " + sensor.type + " at pin " + str(sensor.sensor_pin_int)) - sensor.read() - for measurement in sensor.most_recent_values: - print(f"Got {measurement['value']} {measurement['unit']} ({measurement['type']})") - self.most_recent_values = self.most_recent_values + sensor.most_recent_values - - self.sensor_data_manager.handleData(self.most_recent_values) - - time.sleep(self.device_info.read_secs) - diff --git a/old_version/grow_system_api.py b/old_version/grow_system_api.py deleted file mode 100644 index 8a73310..0000000 --- a/old_version/grow_system_api.py +++ /dev/null @@ -1,38 +0,0 @@ -from http_client import HTTPClient -from device_info import DeviceInfo -import json - - -class GrowSystemApi: - - http_client = HTTPClient() - - device_info = DeviceInfo() - - base_url = '' - - def __init__(self): - self.base_url = self.device_info.server_url - - def activate(self, config): - response = self.http_client.post(self.base_url + "/api/device/activate", self._get_device_data()) - return self_get_json_encoded(response.text) - - def say_hello(self): - response = self.http_client.post(self.base_url + "/api/device", self._get_device_data()) - print(response.text) - jsonResult = json.loads(response.text) - print(jsonResult) - return jsonResult; - - def send_measurements(self, device_id, data): - url = self.base_url + "/api/device/" + str(device_id) + "/sensor-log" - response = self.http_client.post(url, data) - return json.loads(response.text) - - def _get_device_data(self): - return self.device_info.get_all_device_infos() - - def _get_json_encoded(self, text): - return json.loads(text) - diff --git a/old_version/http_client.py b/old_version/http_client.py deleted file mode 100644 index fd197ed..0000000 --- a/old_version/http_client.py +++ /dev/null @@ -1,35 +0,0 @@ -import urequests -import json - -class HTTPClient: - def __init__(self): - pass - - def get(self, url): - url = 'https://' + url - try: - # headers = {'Content-Type': 'application/json'} - response = urequests.get(url) - if response.status_code == 200: - print("Data sent, got response") - return response - else: - print("Failed to get data. Status code:", response.status_code) - except Exception as e: - print("Exception occurred:", e) - - def post(self, url, data): - url = 'https://' + url - try: - headers = {'Content-Type': 'application/json', 'Accept': 'application/json, text/plain, */*'} - json_data = json.dumps(data) - print("Send post request to: " + url) - response = urequests.post(url, data=json_data, headers=headers) - if response.status_code == 200: - return response - else: - print("Failed to send data. Status code:", response.status_code) - print(response.text) - except Exception as e: - print("Exception occurred:", e) - diff --git a/old_version/lib/bh1750.py b/old_version/lib/bh1750.py deleted file mode 100644 index 0f91b49..0000000 --- a/old_version/lib/bh1750.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Micropython BH1750 ambient light sensor driver. -* https://github.com/PinkInk/upylib/tree/master/bh1750 -""" - -from utime import sleep_ms - - -class BH1750(): - """Micropython BH1750 ambient light sensor driver.""" - - PWR_OFF = 0x00 - PWR_ON = 0x01 - RESET = 0x07 - - # modes - CONT_LOWRES = 0x13 - CONT_HIRES_1 = 0x10 - CONT_HIRES_2 = 0x11 - ONCE_HIRES_1 = 0x20 - ONCE_HIRES_2 = 0x21 - ONCE_LOWRES = 0x23 - - # default addr=0x23 if addr pin floating or pulled to ground - # addr=0x5c if addr pin pulled high - def __init__(self, bus, addr=0x23): - self.bus = bus - self.addr = addr - self.off() - self.reset() - - def off(self): - """Turn sensor off.""" - self.set_mode(self.PWR_OFF) - - def on(self): - """Turn sensor on.""" - self.set_mode(self.PWR_ON) - - def reset(self): - """Reset sensor, turn on first if required.""" - self.on() - self.set_mode(self.RESET) - - def set_mode(self, mode): - """Set sensor mode.""" - self.mode = mode - self.bus.writeto(self.addr, bytes([self.mode])) - - def luminance(self, mode): - """Sample luminance (in lux), using specified sensor mode.""" - # continuous modes - if mode & 0x10 and mode != self.mode: - self.set_mode(mode) - # one shot modes - if mode & 0x20: - self.set_mode(mode) - # earlier measurements return previous reading - sleep_ms(24 if mode in (0x13, 0x23) else 180) - data = self.bus.readfrom(self.addr, 2) - factor = 2.0 if mode in (0x11, 0x21) else 1.0 - return (data[0]<<8 | data[1]) / (1.2 * factor) \ No newline at end of file diff --git a/old_version/main.py b/old_version/main.py deleted file mode 100644 index 12935fd..0000000 --- a/old_version/main.py +++ /dev/null @@ -1,63 +0,0 @@ -# GrowSystem -# Author: Maik Müller (maik@muelleronlineorg) - -# WIP! -# This file should do only: -# - first start check and actions if not configured -# - provide constants for settings -# - eventually necessary system settings -# - init wlan connection -# - Call base class, permitting the configured constants -import network -import urequests -from grow_system import GrowSystem -from wlan import WlanClient -from http_client import HTTPClient -from device_info import DeviceInfo -from setup import Setup - - -settings = { - 'wlan_ssid': 'Oppa-95.lan', - 'wlan_pw': '95%04-MM', - 'moisture_sensor': { - 'pin_int': 26 - }, - 'temperature_humidity_sensor': { - 'pin_int': 15 - }, - 'pump_pin_int': 24 -} - - -def wlan_scan(): - # Client-Betrieb - wlan = network.WLAN(network.STA_IF) - # WLAN-Interface aktivieren - wlan.active(True) - # WLANs ausgeben - found_wlans = wlan.scan() - return found_wlans - - -# Press the green button in the gutter to run the script. -if __name__ == '__main__': - pico_setup = Setup() - pico_setup.setup_pico() - - if false: - #print(wlan_scan()) - print("Connect WLAN") - wlanClient = WlanClient(settings['wlan_ssid'], settings['wlan_pw']) - wlanClient.connect() - print("") - - di = DeviceInfo() - print("Device Infos:") - print(di.get_all_device_infos()) - print("") - - print("Start grow system") - gs = GrowSystem(settings) - gs.start() - diff --git a/old_version/moisture_sensor.py b/old_version/moisture_sensor.py deleted file mode 100644 index e11ca76..0000000 --- a/old_version/moisture_sensor.py +++ /dev/null @@ -1,39 +0,0 @@ -# Moisture Sensor Class -from sensors import Sensors -from machine import ADC, Pin - - -class MoistureSensor(Sensors): - - sensor = None - - most_recent_values = [] - - min_raw_value = None - max_raw_value = None - - def __init__(self, sensor_data, min_raw_value=300, max_raw_value=65535): - super().__init__(sensor_data) - print("Initialize moisture sensor. Sensor pin is: " + str(sensor_data['pin_int'])) - self.sensor_pin_int = sensor_data['pin_int'] - self.min_raw_value = min_raw_value - self.max_raw_value = max_raw_value - self.sensor = ADC(Pin(self.sensor_pin_int)) - - def read(self): - self.most_recent_values = [ - { - 'type': 'moisture', - 'value': self.convert_to_moisture_percentage(self.sensor.read_u16()), - 'unit': '%' - }, - ] - - def normalize_sensor_value(self, raw_value): - return (raw_value - self.min_raw_value) / (self.max_raw_value - self.min_raw_value) - - def convert_to_moisture_percentage(self, raw_value): - normalized_value = self.normalize_sensor_value(raw_value) - return round(100 - normalized_value * 100, 1) - - \ No newline at end of file diff --git a/old_version/notes/code_sample_moisture_sensor.txt b/old_version/notes/code_sample_moisture_sensor.txt deleted file mode 100644 index 64a5eaf..0000000 --- a/old_version/notes/code_sample_moisture_sensor.txt +++ /dev/null @@ -1,31 +0,0 @@ -from machine import Pin, ADC -import time -import network -import urequests -import statistics -import secrets -sensor = ADC(Pin(26)) -wlan = network.WLAN(network.STA_IF) -wlan.active(True) -wlan.connect(secrets.SSID, secrets.PASSWORD) -time.sleep(5) -print(wlan.isconnected()) -readings = [] -try: - while True: - for i in range(5): - reading = sensor.read_u16() - readings.append(reading) - print(readings) - time.sleep(1) - median_value = statistics.median(readings) - if median_value < 400: - urequests.get("https://api.telegram.org/bot"+secrets.API+"/sendMessage?text=Gary is thirsty&chat_id="+secrets.ID) - print("Message Sent") - else: - print("Gary has enough water") - time.sleep(3600) -except OSError: - print("@"*68) - print("@ Cannot connect to the Wi-Fi, please check your SSID and PASSWORD @") -print("@"*68) \ No newline at end of file diff --git a/old_version/pump.py b/old_version/pump.py deleted file mode 100644 index fc39e6d..0000000 --- a/old_version/pump.py +++ /dev/null @@ -1,7 +0,0 @@ -from engine import Engine - - -class Pump(Engine): - - def __init__(self, engine): - super().__init__(engine) diff --git a/old_version/sensor_data_manager.py b/old_version/sensor_data_manager.py deleted file mode 100644 index 87dbf39..0000000 --- a/old_version/sensor_data_manager.py +++ /dev/null @@ -1,20 +0,0 @@ -from grow_system_api import GrowSystemApi -# from device_info import DeviceInfo - - -class SensorDataManager: - - device_info = None - - grow_system_api = None - - device_id = None - - def __init__(self, device_id): - self.grow_system_api = GrowSystemApi() - # self.device_info = DeviceInfo() - self.device_id = device_id - - def handleData(self, data): - jsonResponse = self.grow_system_api.send_measurements(self.device_id, data) - print("Response message: " + jsonResponse['message']) \ No newline at end of file diff --git a/old_version/sensors.py b/old_version/sensors.py deleted file mode 100644 index 23ad803..0000000 --- a/old_version/sensors.py +++ /dev/null @@ -1,13 +0,0 @@ -class Sensors: - # this is a parent class for the Sensor classes - sensor_pin_int = -1 - - sensor = None - - type = "unset" - - def __init__(self, settings): - self.type = settings['type'] - print("Initialize " + self.type + " sensor. Sensor pin is: " + str(settings['pin_int'])) - - \ No newline at end of file diff --git a/old_version/setup.py b/old_version/setup.py deleted file mode 100644 index 2aa6cee..0000000 --- a/old_version/setup.py +++ /dev/null @@ -1,113 +0,0 @@ -import network -import ujson -import ure as re -import usocket as socket -import time - -class Setup: - def __init__(self): - self.ap_ssid = "Growsystem" - self.ap_password = "12345678" - self.wlans = [] - self.selected_ssid = "" - self.wlan_password = "" - self.pin = "" - self.html = """ - - Pico Setup - -

Setup Pico

-
- SSID:
- Password:
- PIN:
- -
- - - """ - - def scan_wlans(self): - print("Scan WLANs") - wlan = network.WLAN(network.STA_IF) - wlan.active(True) - self.wlans = [w[0].decode() for w in wlan.scan()] - print("Found:", self.wlans) - wlan.active(False) - - def start_ap_mode(self): - self.ap = network.WLAN(network.AP_IF) - self.ap.active(True) - while self.ap.active() == False: - pass - self.ap.config(essid=self.ap_ssid, password=self.ap_password) - print("AP SSID:", self.ap.config("essid")) - # print("AP Password:", self.ap.config("password")) - - def stop_ap_mode(self): - ap = network.WLAN(network.AP_IF) - ap.active(False) - - def start_webserver(self): - addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] - s = socket.socket() - s.bind(addr) - s.listen(1) - print("Listening on", addr) - while True: - conn, addr = s.accept() - print("Got a connection from", addr) - request = conn.recv(1024) - print("Content =", request) - conn.send("HTTP/1.1 200 OK\n") - conn.send("Content-Type: text/html\n") - conn.send("Connection: close\n\n") - conn.sendall(self.html.format(''.join([''.format(w, w) for w in self.wlans]))) - conn.close() - - def parse_request(self, request): - request = request.decode() - ssid_match = re.search("ssid=([^&]+)", request) - if ssid_match: - self.selected_ssid = ssid_match.group(1) - password_match = re.search("password=([^&]+)", request) - if password_match: - self.wlan_password = password_match.group(1) - pin_match = re.search("pin=([^&]+)", request) - if pin_match: - self.pin = pin_match.group(1) - - def save_config(self): - config = { - "ssid": self.selected_ssid, - "password": self.wlan_password, - "pin": self.pin - } - with open("initial_config.py", "w") as f: - f.write("config = " + ujson.dumps(config)) - - def switch_to_client_mode(self): - ap = network.WLAN(network.AP_IF) - ap.active(False) - wlan = network.WLAN(network.STA_IF) - wlan.active(True) - wlan.connect(self.selected_ssid, self.wlan_password) - while not wlan.isconnected(): - time.sleep(1) - print("Connected to", self.selected_ssid) - - def setup_pico(self): - print("Start PICO setup") - self.scan_wlans() - self.start_ap_mode() - self.start_webserver() - while True: - conn, addr = self.s.accept() - request = conn.recv(1024) - self.parse_request(request) - self.save_config() - conn.close() - break # Assuming only one request is handled - self.stop_ap_mode() - self.switch_to_client_mode() - diff --git a/old_version/wlan.py b/old_version/wlan.py deleted file mode 100644 index c265d8e..0000000 --- a/old_version/wlan.py +++ /dev/null @@ -1,39 +0,0 @@ -import machine -import network -import time -# network.country('DE') - - -class WlanClient: - - ssid = '' - pw = '' - wlan = None - # Status-LED - led_onboard = machine.Pin('LED', machine.Pin.OUT) - led_onboard.value(False) - - def __init__(self, ssid, pw): - # print("Hello from wlan class") - self.ssid = ssid - self.pw = pw - self.wlan = network.WLAN(network.STA_IF) - - def connect(self): - if not self.is_connected(): - print('No WLAN connected. Connecting ...' + self.ssid + ' ' + self.pw) - self.wlan.active(True) - self.wlan.connect(self.ssid, self.pw) - for i in range(10): - if self.wlan.status() < 0 or self.wlan.status() >= 3: - break - time.sleep(1) - # led_value = self.led_onboard.value() == 1 - # self.led_onboard.value(led_value) - if self.wlan.isconnected(): - net_config = self.wlan.ifconfig() - print("NetConfig:") - print(net_config) - - def is_connected(self): - return self.wlan.isconnected() diff --git a/teststuff/main.py b/teststuff/main.py deleted file mode 100644 index 27c3051..0000000 --- a/teststuff/main.py +++ /dev/null @@ -1,50 +0,0 @@ -import network -import time -import socket - -ssid="Growsystem" -password="12345678" - -def web_page(): - html = """ -

Hello World

- """ - return html - -# if you do not see the network you may have to power cycle -# unplug your pico w for 10 seconds and plug it in again -def ap_mode(ssid, password): - """ - Description: This is a function to activate AP mode - - Parameters: - - ssid[str]: The name of your internet connection - password[str]: Password for your internet connection - - Returns: Nada - """ - # Just making our internet connection - ap = network.WLAN(network.AP_IF) - ap.config(essid=ssid, password=password) - ap.active(True) - - while ap.active() == False: - pass - print('AP Mode Is Active, You can Now Connect') - print('IP Address To Connect to:: ' + ap.ifconfig()[0]) - - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #creating socket object - s.bind(('', 80)) - s.listen(5) - - while True: - conn, addr = s.accept() - print('Got a connection from %s' % str(addr)) - request = conn.recv(1024) - print('Content = %s' % str(request)) - response = web_page() - conn.send(response) - conn.close() - -ap_mode('Growsystem95','PASSWORD') \ No newline at end of file -- 2.40.1