Merge branch 'main' into dev
This commit is contained in:
commit
f380c7d7d5
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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():
|
|
||||||
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()
|
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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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)
|
|
||||||
|
|
||||||
40
main.py
40
main.py
|
|
@ -1,10 +1,48 @@
|
||||||
## 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__':
|
||||||
|
# 1) Check and in case of update Growsystem
|
||||||
|
# 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()
|
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()
|
gs.start()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
|
||||||
|
|
@ -77,15 +77,84 @@ 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>
|
||||||
|
<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">
|
<form method="post" action="save">
|
||||||
SSID: <select name="ssid">{}</select><br>
|
<label for="ssid">SSID:</label><br>
|
||||||
Password: <input type="password" name="password"><br><br>
|
<select name="ssid" id="ssid">
|
||||||
ID: <input type="number" name="user_id"/><br/>
|
{}
|
||||||
PIN: <input type="number" name="pin" maxlength="4"><br>
|
</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'):
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue