Compare commits

...

11 Commits

31 changed files with 736 additions and 407 deletions

View File

@ -1,2 +0,0 @@
# GrowSystem

View File

@ -1,3 +0,0 @@
# Show output on terminal #
`minicom -b 115200 -o -D /dev/cu.usbmodem3301`

View File

@ -1 +0,0 @@
from .bh1750 import BH1750

View File

@ -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))

View File

@ -1,62 +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
# }
]
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

View File

@ -1,78 +0,0 @@
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
class GrowSystem:
grow_system_api = GrowSystemApi()
# 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):
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'])
#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)

View File

@ -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/hello", 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()

13
gs/classes/a_sensors.py Normal file
View File

@ -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']))

View File

@ -0,0 +1,73 @@
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)
print("encoding ...", key, value, encoded_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()
}

View File

@ -10,4 +10,4 @@ class Sensors:
self.type = settings['type'] self.type = settings['type']
print("Initialize " + self.type + " sensor. Sensor pin is: " + str(settings['pin_int'])) print("Initialize " + self.type + " sensor. Sensor pin is: " + str(settings['pin_int']))

View File

@ -1,4 +1,4 @@
from sensors import Sensors from gs.classes.a_sensors import Sensors
from machine import Pin, I2C from machine import Pin, I2C
from utime import sleep from utime import sleep
from lib.bh1750 import BH1750 from lib.bh1750 import BH1750
@ -32,3 +32,4 @@ class AmbilightSensor(Sensors):
print('Ambilight Error reading temperature/humidity. Check wires') print('Ambilight Error reading temperature/humidity. Check wires')
print() print()

View File

@ -1,4 +1,4 @@
from sensors import Sensors from gs.classes.a_sensors import Sensors
from dht import DHT22 from dht import DHT22
from machine import ADC, Pin from machine import ADC, Pin
@ -34,3 +34,4 @@ class TemperatureHumiditySensor(Sensors):
except OSError: except OSError:
print('DHT22 Error reading temperature/humidity. Check wires') print('DHT22 Error reading temperature/humidity. Check wires')
print() print()

View File

@ -1,5 +1,5 @@
# Moisture Sensor Class # Moisture Sensor Class
from sensors import Sensors from gs.classes.a_sensors import Sensors
from machine import ADC, Pin from machine import ADC, Pin
@ -36,4 +36,4 @@ class MoistureSensor(Sensors):
normalized_value = self.normalize_sensor_value(raw_value) normalized_value = self.normalize_sensor_value(raw_value)
return round(100 - normalized_value * 100, 1) return round(100 - normalized_value * 100, 1)

4
gs/config/app.py Normal file
View File

@ -0,0 +1,4 @@
dev_api_url = 'api.growsystem.muellerdev.kozow.com'
api_url = 'api.growsystem.muellerdev.kozow.com'
read_secs = 15 * 60
token = "dummy"

View File

@ -0,0 +1 @@
{"sensors": [{"pin_int": 15, "type": "dht22"}, {"pin_int": 26, "type": "moisture"}], "device_id": 9, "name": "Fulltest1", "token": "uStIrOgScrpbUr0Y", "user_id": 1}

View File

@ -0,0 +1 @@
config = {"ssid": "Oppa-95.lan", "user_id": "1", "password": "95%04-MM", "pin": 9534}

66
gs/device_info.py Normal file
View File

@ -0,0 +1,66 @@
import network
import json
class DeviceInfo:
wlan = network.WLAN(network.STA_IF)
app_version = "1.0.0"
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.get_name(),
'mac_address': self.get_macaddress(),
'ip_address': self.get_ipaddress(),
'token': self.get_token()}
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
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
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)
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)

View File

@ -0,0 +1,2 @@
class NotSubscriptableError(Exception):
pass

69
gs/grow_system_api.py Normal file
View File

@ -0,0 +1,69 @@
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
import helper.token_helper as th
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'])
# config = self.device_info.config()
# print("Config:", config)
# print("Test", config['test'])
def activate(self, config):
print("ACtivate config:", 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)
print("REsponse ...", response.content)
return self._get_json_encoded(response.text)
def update_device_info(self, config):
device_id = self.device_info.get_device_id()
token = self.device_info.get_token()
print("update device info. Token ...", token)
url = self.base_url + "/api/device/" + str(device_id) + "/update-device-info/" + token
response = self.http_client.get(url)
print("Device Info Update Response ...", response.text)
return self._get_json_encoded(response.text)
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)
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()
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()

110
gs/growsystem.py Normal file
View File

@ -0,0 +1,110 @@
from gs.device_info import DeviceInfo
import os
import ujson
import machine
import time
from gs.grow_system_api import GrowSystemApi
from gs.classes.sensors.ambilight_sensor import AmbilightSensor
from gs.classes.sensors.dht22 import TemperatureHumiditySensor
from gs.classes.sensors.moisture_sensor import MoistureSensor
import gs.config.initial_config as ic
import helper.token_helper as th
class GrowSystem:
version = "1.0.0.1"
initial_config = None
device_info = DeviceInfo()
sensors = []
def __init__(self):
print("Initialize Growsystem", self.version)
self.initial_config = ic
self.gsapi = GrowSystemApi()
def start(self):
from gs.device_info import DeviceInfo
di = DeviceInfo()
from gs.sensor_data_manager import SensorDataManager
self.sensor_data_manager = SensorDataManager(di.get_device_id())
self._initialize_sensors()
print("Start reading sensors ...")
read_secs = self.device_info.app_config().read_secs
print("Reading and sending every " + str(read_secs) + " seconds")
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 activate(self):
print("Start activation!")
self.initial_config = ic.config
device_config = self.gsapi.activate(self.initial_config)
print("Device Config:", device_config['data'], device_config['data']['token'])
th.write_token(device_config['data']['token'])
self.write_device_infos(device_config['data'])
def update_device_info(self):
print("Start Device Info Update!")
self.initial_config = ic.config
device_config = self.gsapi.update_device_info(self.initial_config)
print("Device Config:", device_config['data'])
self.write_device_infos(device_config['data'])
def write_device_infos(self, device_config):
print("Function received data:", device_config)
if True:
sensors = device_config['sensors']
sensor_configs = []
for sensor in sensors:
sensor_configs.append(sensor['config'])
print(sensor['config'])
device_configs = {
'name': device_config['name'],
'device_id': device_config['id'],
'token': device_config['token'],
'user_id': device_config['user_id'],
'sensors': sensor_configs
}
print("Update device_config.json with:", device_configs)
with open("/gs/config/device_config.json", "w") as f:
f.write(ujson.dumps(device_configs))
f.close()
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'])

View File

@ -9,12 +9,14 @@ class HTTPClient:
url = 'https://' + url url = 'https://' + url
try: try:
# headers = {'Content-Type': 'application/json'} # headers = {'Content-Type': 'application/json'}
print("GET request to: ", url)
response = urequests.get(url) response = urequests.get(url)
if response.status_code == 200: if response.status_code == 200:
print("Data sent, got response") print("Data sent, got response")
return response return response
else: else:
print("Failed to get data. Status code:", response.status_code) print("Failed to get data. Status code:", response.status_code)
return response
except Exception as e: except Exception as e:
print("Exception occurred:", e) print("Exception occurred:", e)
@ -26,10 +28,11 @@ class HTTPClient:
print("Send post request to: " + url) print("Send post request to: " + url)
response = urequests.post(url, data=json_data, headers=headers) response = urequests.post(url, data=json_data, headers=headers)
if response.status_code == 200: if response.status_code == 200:
return response print("Request OK (200)")
else: else:
print("Failed to send data. Status code:", response.status_code) print("Failed to send data.", response.status_code, response.text)
print(response.text) return response
except Exception as e: except Exception as e:
print("Exception occurred:", e) print("Exception raised:", e)
return None

24
gs/sensor_data_manager.py Normal file
View File

@ -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)

View File

@ -37,3 +37,4 @@ class WlanClient:
def is_connected(self): def is_connected(self):
return self.wlan.isconnected() return self.wlan.isconnected()

36
helper/file_helper.py Normal file
View File

@ -0,0 +1,36 @@
config_path = '/gs/config/'
def is_config_existing():
return is_file_existing(config_path + 'device_config.json')
def is_initial_config_existing():
return is_file_existing(config_path + 'initial_config.py')
def is_file_existing(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
def replace_value(filepath, prop, newvalue):
with open(filepath, 'r') as file:
config_lines = file.readlines()
file.close()
# Parse the config data into a dictionary
config_dict = {}
for line in config_lines:
if '=' in line:
key, value = line.strip().split('=')
config_dict[key.strip()] = value.strip()
# Add or Update the value of the property
config_dict[prop] = newvalue
# Write the modified data back to the file
with open(filepath, 'w') as file:
for key, value in config_dict.items():
file.write(f"{key} = {value}\n")

9
helper/token_helper.py Normal file
View File

@ -0,0 +1,9 @@
import helper.file_helper as fh
app_config_path = '/gs/config/app.py'
def write_token(token):
print("Write new token: " + token)
fh.replace_value(app_config_path, 'token', '"' + token + '"')
#with open(app_config_path, "a") as app_config:
# app_config.write(token)

View File

@ -59,4 +59,4 @@ class BH1750():
sleep_ms(24 if mode in (0x13, 0x23) else 180) sleep_ms(24 if mode in (0x13, 0x23) else 180)
data = self.bus.readfrom(self.addr, 2) data = self.bus.readfrom(self.addr, 2)
factor = 2.0 if mode in (0x11, 0x21) else 1.0 factor = 2.0 if mode in (0x11, 0x21) else 1.0
return (data[0]<<8 | data[1]) / (1.2 * factor) return (data[0]<<8 | data[1]) / (1.2 * factor)

96
main.py
View File

@ -1,57 +1,51 @@
# GrowSystem ## Only start grow system
# Author: Maik Müller (maik@muelleronlineorg) from time import sleep
import helper.file_helper as fh
# WIP! if False:
# This file should do only: if not self._is_initial_config_existing():
# - provide constants for settings print("No config existing. Start setup ...")
# - eventually necessary system settings self._setup()
# - init wlan connection return
# - Call base class, permitting the configured constants
import network from gs.sensor_data_manager import SensorDataManager
import urequests self.sensor_data_manager = SensorDataManager(self.device_info.get_device_id())
from grow_system import GrowSystem from gs.grow_system_api import GrowSystemApi as GSA
from wlan import WlanClient self.gsapi = GSA()
from http_client import HTTPClient
from device_info import DeviceInfo 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 setup():
from setup.setup import Setup
setup = Setup()
setup.setup_pico()
machine.reset
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__': if __name__ == '__main__':
#print(wlan_scan()) # 1) Check and in case of update Growsystem
print("Connect WLAN") # 2) Check if initial_config is existing -> Setup if not
wlanClient = WlanClient(settings['wlan_ssid'], settings['wlan_pw'])
wlanClient.connect()
print("")
di = DeviceInfo() if not fh.is_initial_config_existing():
print("Device Infos:") setup()
print(di.get_all_device_infos()) else:
print("") from gs.growsystem import GrowSystem
gs = GrowSystem()
# 3) if device info exists update Device Info else activate
if fh.is_config_existing():
gs.update_device_info()
else:
gs.activate()
# 4) Start growsystem
gs.start()
print("Start grow system") while True:
gs = GrowSystem(settings) print("Keep running in main.py")
gs.start() sleep(5)

View File

@ -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)

View File

@ -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'])

180
setup/little_apache.py Normal file
View File

@ -0,0 +1,180 @@
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"""
<!DOCTYPE html>
<html>
<head>
<title>Growsystem</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
"""
footer = f"""
</body>
</html>
"""
body = ""
if self.is_path_match(request, '/test1'):
body = f"""
<div>Test 1!!!</div>
"""
elif (self.is_path_match(request, '') or self.is_path_match(request, '/')):
options = []
for w in self.available_wifis:
options.append('<option value="{}">{}</option>'.format(w, w))
body = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Growsystem Setup</title>
<style>
body {{
font-family: Arial, sans-serif;
background-color: #f2f2f2;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}}
form {{
background-color: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
max-width: 400px;
width: 100%;
}}
h1 {{
text-align: center;
color: #333;
}}
input[type="submit"] {{
background-color: #4CAF50;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}}
input[type="submit"]:hover {{
background-color: #45a049;
}}
input[type="text"],
input[type="password"],
input[type="number"],
select {{
width: 100%;
padding: 10px;
margin: 5px 0;
border: 1px solid #ccc;
border-radius: 5px;
box-sizing: border-box;
}}
</style>
</head>
<body>
<h1>Growsystem Setup</h1>
<form method="post" action="save">
<label for="ssid">SSID:</label><br>
<select name="ssid" id="ssid">
{}
</select><br>
<label for="password">Password:</label><br>
<input type="password" name="password" id="password"><br><br>
<label for="user_id">ID:</label><br>
<input type="number" name="user_id" id="user_id"><br>
<label for="pin">PIN:</label><br>
<input type="number" name="pin" id="pin" maxlength="4"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
"""
body = body.format(''.join(options))
elif self.is_path_match(request, '/save', 'POST'):
print("Save config path: ", request)
self.keep_webserver_alive = False
body = """
<h1>Setup Pico</h1>
<div>Setup abgeschlossen. Bitte ein paar Sekunden warten, dann neu starten.</div>
"""
else:
body = f"""
<div>Unknown page</div>
"""
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

87
setup/setup.py Normal file
View File

@ -0,0 +1,87 @@
import network
import ujson
import ure as re
import usocket as socket
import time
from setup.little_apache import LittleApache
class Setup:
wlans = []
def __init__(self):
print("Start Pico Setup")
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'],
"user_id": config['user_id']
}
print("Save initial 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()