Merge branch 'main' into dev

This commit is contained in:
Maik Müller 2024-05-09 17:17:28 +02:00
commit f380c7d7d5
11 changed files with 222 additions and 112 deletions

View File

@ -51,7 +51,8 @@ class HttpRequest:
# Encode the values in the dictionary # Encode the values in the dictionary
encoded_content = {} encoded_content = {}
for key, value in parsed_content.items(): 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_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 encoded_content[key] = encoded_value
return encoded_content return encoded_content

View File

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

View File

@ -3,6 +3,7 @@ from gs.device_info import DeviceInfo
from gs.wlan_client import WlanClient from gs.wlan_client import WlanClient
import json import json
import gs.config.initial_config as ic import gs.config.initial_config as ic
import helper.token_helper as th
class GrowSystemApi: class GrowSystemApi:
@ -30,15 +31,19 @@ class GrowSystemApi:
}) })
print("activate ...", data) print("activate ...", data)
response = self.http_client.post(self.base_url + "/api/device/activate", data) response = self.http_client.post(self.base_url + "/api/device/activate", data)
print("REsponse ...", response) print("REsponse ...", response.content)
return self._get_json_encoded(response.text) return self._get_json_encoded(response.text)
def say_hello(self): def update_device_info(self, config):
response = self.http_client.post(self.base_url + "/api/device", self._get_device_data()) device_id = self.device_info.get_device_id()
print(response.text)
jsonResult = json.loads(response.text) token = self.device_info.get_token()
print(jsonResult)
return jsonResult; 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): def send_measurements(self, device_id, data):
url = self.base_url + "/api/device/" + str(device_id) + "/sensor-log" url = self.base_url + "/api/device/" + str(device_id) + "/sensor-log"

View File

@ -1,18 +1,18 @@
from gs.setup import Setup
from gs.device_info import DeviceInfo from gs.device_info import DeviceInfo
from gs.sensor_data_manager import SensorDataManager
import os import os
import ujson import ujson
import machine import machine
import time import time
from gs.grow_system_api import GrowSystemApi
from gs.classes.sensors.ambilight_sensor import AmbilightSensor from gs.classes.sensors.ambilight_sensor import AmbilightSensor
from gs.classes.sensors.dht22 import TemperatureHumiditySensor from gs.classes.sensors.dht22 import TemperatureHumiditySensor
from gs.classes.sensors.moisture_sensor import MoistureSensor from gs.classes.sensors.moisture_sensor import MoistureSensor
import gs.config.initial_config as ic
import helper.token_helper as th
class GrowSystem: class GrowSystem:
version = "1.0" version = "1.0.0.1"
initial_config = None initial_config = None
@ -22,29 +22,20 @@ class GrowSystem:
def __init__(self): def __init__(self):
print("Initialize Growsystem", self.version) print("Initialize Growsystem", self.version)
self.initial_config = ic
if not self._is_initial_config_existing(): self.gsapi = GrowSystemApi()
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.")
self._initialize_sensors()
elif self._is_initial_config_existing():
print("Initial config only existing (no base config). Start activation ...")
self._activate()
def start(self): def start(self):
self.sensor_data_manager = SensorDataManager(self.device_info.get_device_id()) 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 ...") print("Start reading sensors ...")
read_secs = self.device_info.app_config().read_secs read_secs = self.device_info.app_config().read_secs
print("Reading and sending every " + str(read_secs) + " seconds")
while True: while True:
# Reset data # Reset data
self.most_recent_values = [] self.most_recent_values = []
@ -60,51 +51,41 @@ class GrowSystem:
time.sleep(read_secs) time.sleep(read_secs)
def _setup(self): def activate(self):
setup = Setup()
setup.setup_pico()
machine.reset
def _activate(self):
print("Start activation!") print("Start activation!")
import gs.config.initial_config as ic
self.initial_config = ic.config self.initial_config = ic.config
device_config = self.gsapi.activate(self.initial_config) device_config = self.gsapi.activate(self.initial_config)
#print("Device Config:", device_config['data']) 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: if True:
sensors = device_config['data']['sensors'] sensors = device_config['sensors']
sensor_configs = [] sensor_configs = []
for sensor in sensors: for sensor in sensors:
sensor_configs.append(sensor['config']) sensor_configs.append(sensor['config'])
print(sensor['config']) print(sensor['config'])
device_configs = { device_configs = {
'name': device_config['data']['name'], 'name': device_config['name'],
'device_id': device_config['data']['id'], 'device_id': device_config['id'],
'token': device_config['data']['token'], 'token': device_config['token'],
'user_id': device_config['data']['user_id'], 'user_id': device_config['user_id'],
'sensors': sensor_configs 'sensors': sensor_configs
} }
print("Update device_config.json with:", device_configs)
with open("/gs/config/device_config.json", "w") as f: with open("/gs/config/device_config.json", "w") as f:
f.write(ujson.dumps(device_configs)) f.write(ujson.dumps(device_configs))
if self._is_config_existing(): f.close()
machine.reset
def _is_config_existing(self):
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')
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
def _initialize_sensors(self): def _initialize_sensors(self):
# Init sensors # Init sensors

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)

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

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

44
main.py
View File

@ -1,11 +1,49 @@
## Only start grow system ## Only start grow system
from gs.growsystem import GrowSystem
from time import sleep from time import sleep
import helper.file_helper as fh
if False:
if not self._is_initial_config_existing():
print("No config existing. Start setup ...")
self._setup()
return
from gs.sensor_data_manager import SensorDataManager
self.sensor_data_manager = SensorDataManager(self.device_info.get_device_id())
from gs.grow_system_api import GrowSystemApi as GSA
self.gsapi = GSA()
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
if __name__ == '__main__': if __name__ == '__main__':
gs = GrowSystem() # 1) Check and in case of update Growsystem
gs.start() # 2) Check if initial_config is existing -> Setup if not
if not fh.is_initial_config_existing():
setup()
else:
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()
while True: while True:
print("Keep running in main.py") print("Keep running in main.py")

View File

@ -77,16 +77,85 @@ class LittleApache():
options = [] options = []
for w in self.available_wifis: for w in self.available_wifis:
options.append('<option value="{}">{}</option>'.format(w, w)) options.append('<option value="{}">{}</option>'.format(w, w))
body = """ body = """
<h1>Setup Pico</h1> <!DOCTYPE html>
<form method="post" action="save"> <html lang="en">
SSID: <select name="ssid">{}</select><br> <head>
Password: <input type="password" name="password"><br><br> <meta charset="UTF-8">
ID: <input type="number" name="user_id"/><br/> <meta name="viewport" content="width=device-width, initial-scale=1.0">
PIN: <input type="number" name="pin" maxlength="4"><br> <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"> <input type="submit" value="Submit">
</form> </form>
""" </body>
</html>
"""
body = body.format(''.join(options)) body = body.format(''.join(options))
elif self.is_path_match(request, '/save', 'POST'): elif self.is_path_match(request, '/save', 'POST'):
print("Save config path: ", request) print("Save config path: ", request)
@ -99,7 +168,6 @@ class LittleApache():
body = f""" body = f"""
<div>Unknown page</div> <div>Unknown page</div>
""" """
html = '' html = ''
html_arr = [header, body, footer] html_arr = [header, body, footer]
html = html.join(html_arr) html = html.join(html_arr)
@ -109,3 +177,4 @@ class LittleApache():
return path == request.path and method == request.method return path == request.path and method == request.method

View File

@ -3,7 +3,7 @@ import ujson
import ure as re import ure as re
import usocket as socket import usocket as socket
import time import time
from gs.little_apache import LittleApache from setup.little_apache import LittleApache
class Setup: class Setup:
@ -11,6 +11,7 @@ class Setup:
wlans = [] wlans = []
def __init__(self): def __init__(self):
print("Start Pico Setup")
self.ap_ssid = "Growsystem 1.0" self.ap_ssid = "Growsystem 1.0"
self.ap_password = "password" self.ap_password = "password"
self.wlans = [] self.wlans = []
@ -83,3 +84,4 @@ class Setup:
# self.stop_ap_mode() # self.stop_ap_mode()
# self.switch_to_client_mode() # self.switch_to_client_mode()