-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathToDo
190 lines (162 loc) · 10 KB
/
ToDo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
aquaPi ToDo list
================
- Known defects:
# logging: resolve the abuse of logging.WARNING as loglevel.BRIEF; log.verbose() could be a functools.partialmethod(log.log, loglevel.INFO-1,...)
# REAL_CONFIG: GPIO13 must be permanently on (Filter!) - might need a new ConstInput(100)
# startup behaviour of bus isn't good - let everybody post its data as response to HELLO?
# on Raspi driver TC420 finds a device although there's none
- Navigation:
/ Home, a configurable dashboard
/settings Controllers, with foldable groups containing Controllers & their in/out
This page views and allows to edit operation parameters (Temp, Schedule)
Edit needs auth.??
/config Configuration, show all bus nodes, their relations, or /modules ?
Allow authenticated users to add/change/remove nodes on the bus.
/system Global configuration, users, email, logging, start/stop, update ...
Authenticated, at least some actions.
/log View logs with errors, warnings and configured events.
/about some system information, help pointers
- Add group as new property to each Controller, set by user, default ""
Allow group filtering or foldable groups in Dashboard
- add a route for log & errors - backend implemented as BusListener?
- initial setup could be simplified by module templates,
i.e. std controller combos (pickled/json?) for common functions with a wizzard
this postpones the need for advanced config UI
- related: allow (re-) config via command line option (json file)
- simple UI & advanced UI, to allow easy start; simple = no AUX nodes!?
- Nodes:
controller: null (out=in), delay
input: schedule analog?, random
aux: min, limiter
misc: email, telegram, history, cloud telemetry, macro
UI node: shows data when configured as listener, else UI input is posted to bus
- macros!?! = scheduled/triggered sender of msgs on the bus? wait for msgs?
This will require affected nodes to supended their listening to avoid conflicts.
Not fully clear how this can work.
- input/output drivers, auto-detect where possible:
File in, Shelly in?
PWM pca9685, Shelly Relay, File out, shell script
- pH probe: JBL describes aging of probes. A new probe has 0mV @ pH7 and 186mV @ pH4. When calibrating an offset of > +/-40mV or a voltage diff of < 90mV between pH7 and pH4 their controller rejects a probe.
- user authentication: use Flask.redirect() & session
three access levels: viewer / operator (e.g. temperature setpoints) / admin (full config)
- add 'click' cmdline options, e.g. --resetfactory --list ...
- use Flask-Babel for backend i18n & l10 / frontend is prepared
ref: https://github.com/python-babel/flask-babel
ref: https://flask-babel.tkte.ch/
- REST API: some endpoints return text, others json, should be all json
- wallneradam/tc420 is forked to shcwabix-1311/tc420, PRs 11/12/13 and more are applied there,
using a git submodule to integrate it, installation must be reviewd:
pip install tc420 (->requirements.txt); (addgroup plugdev); adduser <user> plugdev; cp 99-7c420.rules /etc/udev/rules.d/
adapter µUSB->USB A plus cable USB A -> USB B
- Telegram bot in Python:
package pyTelegramBotAPI,
https://thepythoncorner.com/posts/2021-01-16-how-create-telegram-bot-in-python/
in channel BotFather /newbot: name aquaPi, bot @UNIQUE_bot, remeber bot token,
find own "chat id": https://web.telegram.org/z/#?tgaddr=tg://resolve?domain=schwabix,
this redirects to a URL ending in your chat id
OR join and start @RawDataBot, it will reply with json showing your chat:id
OR join and start your bot, then https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates
send message - 8135... is bot token, 1261... is chat id - multiple subscribers??:
https://api.telegram.org/botXXXXXXXXX:AAEQ0ec6XT6i0BSvF3ldVrmepETMTjyxNiE/sendMessage?chat_id=XXXXXXXXX&text=bot6135_to_1261..
and modify/update it:
https://api.telegram.org/botXXXXXXXXX:AAEQ0ec6XT6i0BSvF3ldVrmepETMTjyxNiE/editMessageText?message_id=2983&chat_id=XXXXXXXXX&text=changed_Text
get message history (depth?), could be used to receive commands:
https://api.telegram.org/botYYYYYYYYYY:AAHH4nCC-vD8clvfiMryls_ZpdJi_HskctM/getUpdates
sample ->
{"ok":true,"result":[{"update_id":23832511,
"message":{"message_id":1,"from":{"id":126177523,"is_bot":false,"first_name":"Markus","username":"schwabix","language_code":"de"},"chat":{"id":126177523,"first_name":"Markus","username":"schwabix","type":"private"},"date":1691342697,"text":"/start","entities":[{"offset":0,"length":6,"type":"bot_command"}]}},{"update_id":23832512,
...
"message":{"message_id":7,"from":{"id":126177523,"is_bot":false,"first_name":"Markus","username":"schwabix","language_code":"de"},"chat":{"id":126177523,"first_name":"Markus","username":"schwabix","type":"private"},"date":1691343059,"text":"soso"}},{"update_id":23832516,
"message":{"message_id":10,"from":{"id":126177523,"is_bot":false,"first_name":"Markus","username":"schwabix","language_code":"de"},"chat":{"id":126177523,"first_name":"Markus","username":"schwabix","type":"private"},"date":1691343182,"text":"silence"}}]}
or bot as group member allows multiple receivers, but only 1 bot??:
https://api.telegram.org/botYYYYYYYYYY:AAHH4nCC-vD8clvfiMryls_ZpdJi_HskctM/sendMessage?chat_id=-978207359&text=ph%20Alarm!
OR simple sample without dedicated package!!:
https://medium.com/codex/using-python-to-send-telegram-messages-in-3-simple-steps-419a8b5e5e2
- packaging and deployment ... long way to there!
- not so common features:
multiple sensors can feed one control unit (redundancy=safety),
several control units can drive one output in a predictible manner,
logging/email alerts for virtually anything,
over-temperature could dim the light or let a fan spin up:
min(LightCtrl, clipped result of a inversly scaled temperature) -> AnalogOut
too low pH could turn on light (to let plants consume CO2)
heuristics to recommend filter cleaning, based on reduced flow ->
temperature diffs, rotating wave?
utilization -> heater dimension, CO2 valve setting/empty
luxmeter??
THOUGHTS
========
- python & Flask are closer to my skills and work style, than NodeJS and its huge library of tiny modules (introduces many dependencies requiring permanent updates). Same might be the case with Django.
- Task Queues like huey could be used instead of my own MsgBus, but it requires exploration until I know where its limits are. For MsgBus I know them and can hopefully solve them.
DONE
====
- manually, global: pip pip install pylint, vim-jedi, jedi-language-server, vim-ale
- manually modify .vimrc:
let g:ale_linters = {
\ 'python': ['flake8', 'pylint', 'jedils'],
\ 'javascript': ['eslint'],
\}
let g:ale_fixers = {
\ 'python': ['autoflake', 'autopep8', 'black'],
\}
nmap gd :ALEGoToDefinition<CR> " because I prefer tabs
nmap gr :ALEFindReferences<CR>
nmap K :ALEHover<CR>
let g:ale_completion_enabled = 1
set omnifunc=ale#completion#OmniFunc
- init
python -m venv venv
. ./venv/bin/activate
pip install Flask sseclient ...
- run
export FLASK_APP=aquaPi
export FLASK_ENV=development
flask run
- proof of concept for front-end updates:
push data from backend to UI, use page reload/Ajax/websocket/SSE? SSE to trigger REST!
ref: https://stackoverflow.com/questions/13386681/streaming-data-with-python-and-flask
ref: https://javascript.info/server-sent-events
- sample with interaction of MsgListener with SSE-consuming page
- put the project on github. Or somewhere else? Unlikely
- use Jinja template inheritance, so far just plain templates are used
- cleanup the project name: 'aquaPi' (lowercase i), but home directory is
aquaPI (upper!) to distinguish it from the app directory
- Flask in debug mode reloaded everything without cleanup, duplicating worker threads, etc.,
at least the 1st reload is now handled correctly, still no atexit-cleanup
- milestones for machine room:
a) simple sensor-temperature-relais controller
b) 2 temperature controllers with redundant sensors and overlapping outputs
c) scheduled light controller
- milestone for backend:
save configuration and restore during startup (instead of hard-coded topology!)
Evaluate pickle vs. shelve vs. klepto
ref: https://pynative.com/make-python-class-json-serializable/ ??
ref: https://pynative.com/python-convert-json-data-into-custom-python-object/ #jsonpickle
ref: https://stackoverflow.com/questions/14668475/pickle-versus-shelve-storing-large-dictionaries-in-python/32586980#32586980
- milestones for UI:
a) change temperature threshold via web UI
b) change light schedule via web UI
Use html form & POST/PUT for now. Might need redesign for REST.
- register a cleanup method with atexit() to save config, and to get along
with werkzeug's neat auto-reload
- explore Flask.flash() - for input validation message
- input/output drivers, auto-detect where possible:
GPIOin switch, DS1820, ADS1115
GPIOout switch, hardware PWM
- Nodes:
controller: minimum, maximum, fader, sun
input: switch, analog, schedule switch
output: switch, analog
aux: max, average, calibration (scaler)
- OS Sleep/Resume disturbs scheduler - fixed
- config persistance - DB or pickle file? overlap of instance/aquaPi.sqlite & aquaPi/db.py?
general handling of config data
=> machineroom config is pickled, user prefs are in browser store,
- might need additional app global config in back end for
e.g. UI groups, time zone, language, etc. QuestDB is usable for this
- DB for history: InfluxDB 1.6.4 loked OK, but irregular time series aren't
handled correctly in subsampled queries. Switched to QuestDB, which needs
a 64bit OS; will use an in-memory storage for 32bit with minimal funtionality.
- unique feature is a driver interface to a TC420 light controller,
wallneradam/tc420 on github is a Linux shell tool to interact with TC420
- thanks to Thomas migrated most from Jinja templates via Vue to Vuetify