Merged documents into ultrasonic sensor stuff
This commit is contained in:
commit
04bfaf4d94
31
README.md
31
README.md
@ -1,16 +1,25 @@
|
|||||||
# PlantCtrl
|
# PlantCtrl
|
||||||
## Documentation of Power-Modes
|
|
||||||
https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/#esp32-deep-sleep
|
|
||||||
|
|
||||||
|
The following problems shall be solved with this project:
|
||||||
|
* Solar Powered
|
||||||
|
* Low Powered
|
||||||
|
* Plant monitoring
|
||||||
|
* Plant watering
|
||||||
|
* IoT
|
||||||
|
|
||||||
gpio 17 only out no hold
|
# Hardware
|
||||||
gpio 16 only out no hold
|
Open hardware design (powered by KiCAD).
|
||||||
|
The complete PCB is stored in the ***board*** sub directory.
|
||||||
|
|
||||||
|
There the following components are connected:
|
||||||
|
* ESP32 NodeMCU Module (the one of A-Z Delivery was used)
|
||||||
|
* Lipo
|
||||||
|
* 7 moist sensors
|
||||||
|
* 7 pump
|
||||||
|
* DC-DC convert (generating voltage from Lipo for pumps)
|
||||||
|
* DS18B20 temperature sensors
|
||||||
|
* water tank ultrasonic sensor (via HC_SR04)
|
||||||
|
* general purpose expansion pin
|
||||||
|
|
||||||
solar charger 2A?
|
# Software
|
||||||
https://www.aliexpress.com/item/4000238259949.html?spm=a2g0o.productlist.0.0.7e50231cCWGu0Z&algo_pvid=9ab7b0d3-5026-438b-972b-1d4a81d4dc56&algo_expid=9ab7b0d3-5026-438b-972b-1d4a81d4dc56-11&btsid=0b0a0ac215999246489888249e72a9&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_
|
The firmware for the controller is stored in ***esp32*** sub directory.
|
||||||
|
|
||||||
MT3608 boost für pumpe
|
|
||||||
https://www.aliexpress.com/item/32925951391.html?spm=a2g0o.productlist.0.0.39e21087nAzH9q&algo_pvid=7db0a849-62f7-4403-88e3-615ee4d99339&algo_expid=7db0a849-62f7-4403-88e3-615ee4d99339-0&btsid=0b0a0ac215999252934777876e7253&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_
|
|
||||||
|
|
||||||
DS18B20 one wire temp sensor
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -4,10 +4,10 @@ EELAYER END
|
|||||||
$Descr A4 11693 8268
|
$Descr A4 11693 8268
|
||||||
encoding utf-8
|
encoding utf-8
|
||||||
Sheet 1 1
|
Sheet 1 1
|
||||||
Title ""
|
Title "Plant Controller"
|
||||||
Date ""
|
Date "2020-11-11"
|
||||||
Rev ""
|
Rev "0.3"
|
||||||
Comp ""
|
Comp "C3MA"
|
||||||
Comment1 ""
|
Comment1 ""
|
||||||
Comment2 ""
|
Comment2 ""
|
||||||
Comment3 ""
|
Comment3 ""
|
||||||
@ -134,7 +134,7 @@ Text GLabel 1150 2050 0 50 Input ~ 0
|
|||||||
PLANT6_PUMP
|
PLANT6_PUMP
|
||||||
Text Notes 950 550 0 50 ~ 0
|
Text Notes 950 550 0 50 ~ 0
|
||||||
Pump Control
|
Pump Control
|
||||||
Text Notes 1100 5400 0 50 ~ 0
|
Text Notes 2600 7500 0 50 ~ 0
|
||||||
Lipo
|
Lipo
|
||||||
Text Notes 4050 2650 1 50 ~ 0
|
Text Notes 4050 2650 1 50 ~ 0
|
||||||
Sensors
|
Sensors
|
||||||
@ -542,44 +542,44 @@ Wire Wire Line
|
|||||||
$Comp
|
$Comp
|
||||||
L Connector_Generic:Conn_01x04 J3
|
L Connector_Generic:Conn_01x04 J3
|
||||||
U 1 1 5F837F50
|
U 1 1 5F837F50
|
||||||
P 1750 3150
|
P 1600 2750
|
||||||
F 0 "J3" H 1830 3142 50 0000 L CNN
|
F 0 "J3" H 1680 2742 50 0000 L CNN
|
||||||
F 1 "Conn_01x04" H 1830 3051 50 0000 L CNN
|
F 1 "Conn_01x04" H 1680 2651 50 0000 L CNN
|
||||||
F 2 "misc_footprints:MT3608_module_SMT" H 1750 3150 50 0001 C CNN
|
F 2 "misc_footprints:MT3608_module_SMT" H 1600 2750 50 0001 C CNN
|
||||||
F 3 "~" H 1750 3150 50 0001 C CNN
|
F 3 "~" H 1600 2750 50 0001 C CNN
|
||||||
1 1750 3150
|
1 1600 2750
|
||||||
1 0 0 -1
|
1 0 0 -1
|
||||||
$EndComp
|
$EndComp
|
||||||
Text GLabel 1550 3050 0 50 Input ~ 0
|
Text GLabel 1400 2650 0 50 Input ~ 0
|
||||||
PWR_PUMP_CONVERTER
|
PWR_PUMP_CONVERTER
|
||||||
Text GLabel 1550 3150 0 50 Input ~ 0
|
Text GLabel 1400 2750 0 50 Input ~ 0
|
||||||
GND
|
GND
|
||||||
Text GLabel 1550 3250 0 50 Input ~ 0
|
Text GLabel 1400 2850 0 50 Input ~ 0
|
||||||
GND
|
GND
|
||||||
Text GLabel 1550 3350 0 50 Input ~ 0
|
Text GLabel 1400 2950 0 50 Input ~ 0
|
||||||
PUMP_PWR
|
PUMP_PWR
|
||||||
$Comp
|
$Comp
|
||||||
L LP38690DT-3.3:LP38690DT-3.3 U3
|
L LP38690DT-3.3:LP38690DT-3.3 U3
|
||||||
U 1 1 5F84FA14
|
U 1 1 5F84FA14
|
||||||
P 1400 5300
|
P 2900 7400
|
||||||
F 0 "U3" H 1400 5665 50 0000 C CNN
|
F 0 "U3" H 2900 7765 50 0000 C CNN
|
||||||
F 1 "LP38690DT-3.3" H 1400 5574 50 0000 C CNN
|
F 1 "LP38690DT-3.3" H 2900 7674 50 0000 C CNN
|
||||||
F 2 "ESP32:DPAK457P991X255-3N" H 1400 5300 50 0001 L BNN
|
F 2 "ESP32:DPAK457P991X255-3N" H 2900 7400 50 0001 L BNN
|
||||||
F 3 "IPC-7351B" H 1400 5300 50 0001 L BNN
|
F 3 "IPC-7351B" H 2900 7400 50 0001 L BNN
|
||||||
F 4 "Texas Instruments" H 1400 5300 50 0001 L BNN "Field4"
|
F 4 "Texas Instruments" H 2900 7400 50 0001 L BNN "Field4"
|
||||||
F 5 "M" H 1400 5300 50 0001 L BNN "Field5"
|
F 5 "M" H 2900 7400 50 0001 L BNN "Field5"
|
||||||
F 6 "2.55mm" H 1400 5300 50 0001 L BNN "Field6"
|
F 6 "2.55mm" H 2900 7400 50 0001 L BNN "Field6"
|
||||||
1 1400 5300
|
1 2900 7400
|
||||||
1 0 0 -1
|
1 0 0 -1
|
||||||
$EndComp
|
$EndComp
|
||||||
Text GLabel 2000 5400 2 50 Input ~ 0
|
Text GLabel 3500 7500 2 50 Input ~ 0
|
||||||
GND
|
GND
|
||||||
Text GLabel 2000 5200 2 50 Input ~ 0
|
Text GLabel 3500 7300 2 50 Input ~ 0
|
||||||
3_3V
|
3_3V
|
||||||
Text GLabel 4150 5700 0 50 Input ~ 0
|
Text GLabel 4150 5700 0 50 Input ~ 0
|
||||||
3_3V
|
3_3V
|
||||||
NoConn ~ 4200 7500
|
NoConn ~ 4200 7500
|
||||||
Text GLabel 800 5200 0 50 Input ~ 0
|
Text GLabel 2300 7300 0 50 Input ~ 0
|
||||||
LIPO+
|
LIPO+
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
10550 6100 10700 6100
|
10550 6100 10700 6100
|
||||||
@ -1004,37 +1004,28 @@ CUSTOM_GPIO
|
|||||||
$Comp
|
$Comp
|
||||||
L Connector:Conn_01x02_Female J4
|
L Connector:Conn_01x02_Female J4
|
||||||
U 1 1 5F8D742C
|
U 1 1 5F8D742C
|
||||||
P 1300 4100
|
P 3050 4300
|
||||||
F 0 "J4" H 1328 4076 50 0000 L CNN
|
F 0 "J4" H 3078 4276 50 0000 L CNN
|
||||||
F 1 "Conn_01x02_Female" H 1000 3900 50 0000 L CNN
|
F 1 "Conn_01x02_Female" H 2450 4100 50 0000 L CNN
|
||||||
F 2 "misc_footprints:BatteryHolder_Keystone_1042_1x18650" H 1300 4100 50 0001 C CNN
|
F 2 "misc_footprints:BatteryHolder_Keystone_1042_1x18650" H 3050 4300 50 0001 C CNN
|
||||||
F 3 "~" H 1300 4100 50 0001 C CNN
|
F 3 "~" H 3050 4300 50 0001 C CNN
|
||||||
1 1300 4100
|
1 3050 4300
|
||||||
1 0 0 -1
|
1 0 0 -1
|
||||||
$EndComp
|
$EndComp
|
||||||
Text Notes 1200 4000 0 50 ~ 0
|
Text Notes 1300 3850 0 50 ~ 0
|
||||||
Fuse for Lipo
|
Protection for Lipo
|
||||||
Text GLabel 900 4200 0 50 Input ~ 0
|
|
||||||
GND
|
|
||||||
Wire Wire Line
|
|
||||||
900 4200 950 4200
|
|
||||||
$Comp
|
$Comp
|
||||||
L power:GND #PWR0120
|
L power:GND #PWR0120
|
||||||
U 1 1 5F95011F
|
U 1 1 5F95011F
|
||||||
P 950 4450
|
P 2000 5200
|
||||||
F 0 "#PWR0120" H 950 4200 50 0001 C CNN
|
F 0 "#PWR0120" H 2000 4950 50 0001 C CNN
|
||||||
F 1 "GND" H 955 4277 50 0000 C CNN
|
F 1 "GND" H 2005 5027 50 0000 C CNN
|
||||||
F 2 "" H 950 4450 50 0001 C CNN
|
F 2 "" H 2000 5200 50 0001 C CNN
|
||||||
F 3 "" H 950 4450 50 0001 C CNN
|
F 3 "" H 2000 5200 50 0001 C CNN
|
||||||
1 950 4450
|
1 2000 5200
|
||||||
1 0 0 -1
|
1 0 0 -1
|
||||||
$EndComp
|
$EndComp
|
||||||
Wire Wire Line
|
Text Notes 750 2550 0 50 ~ 0
|
||||||
950 4450 950 4200
|
|
||||||
Connection ~ 950 4200
|
|
||||||
Wire Wire Line
|
|
||||||
950 4200 1100 4200
|
|
||||||
Text Notes 900 2950 0 50 ~ 0
|
|
||||||
Pump Voltage Converter
|
Pump Voltage Converter
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
11050 6250 11050 6300
|
11050 6250 11050 6300
|
||||||
@ -1049,21 +1040,21 @@ F 3 "~" H 3050 2550 50 0001 C CNN
|
|||||||
1 3050 2550
|
1 3050 2550
|
||||||
1 0 0 -1
|
1 0 0 -1
|
||||||
$EndComp
|
$EndComp
|
||||||
Text GLabel 2350 2750 0 50 Input ~ 0
|
Text GLabel 2500 2750 0 50 Input ~ 0
|
||||||
PWR_SENSORS
|
PWR_SENSORS
|
||||||
Text GLabel 2350 2650 0 50 Input ~ 0
|
Text GLabel 2500 2650 0 50 Input ~ 0
|
||||||
TANK_TRIGGER
|
TANK_TRIGGER
|
||||||
Text GLabel 2350 2550 0 50 Input ~ 0
|
Text GLabel 2500 2550 0 50 Input ~ 0
|
||||||
TANK_ECHO
|
TANK_ECHO
|
||||||
$Comp
|
$Comp
|
||||||
L power:GND #PWR0121
|
L power:GND #PWR0121
|
||||||
U 1 1 5F9F8100
|
U 1 1 5F9F8100
|
||||||
P 2850 2450
|
P 2500 2450
|
||||||
F 0 "#PWR0121" H 2850 2200 50 0001 C CNN
|
F 0 "#PWR0121" H 2500 2200 50 0001 C CNN
|
||||||
F 1 "GND" V 2855 2322 50 0000 R CNN
|
F 1 "GND" V 2505 2322 50 0000 R CNN
|
||||||
F 2 "" H 2850 2450 50 0001 C CNN
|
F 2 "" H 2500 2450 50 0001 C CNN
|
||||||
F 3 "" H 2850 2450 50 0001 C CNN
|
F 3 "" H 2500 2450 50 0001 C CNN
|
||||||
1 2850 2450
|
1 2500 2450
|
||||||
0 1 1 0
|
0 1 1 0
|
||||||
$EndComp
|
$EndComp
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
@ -1082,15 +1073,14 @@ $EndComp
|
|||||||
$Comp
|
$Comp
|
||||||
L power:PWR_FLAG #FLG0101
|
L power:PWR_FLAG #FLG0101
|
||||||
U 1 1 5FA3662A
|
U 1 1 5FA3662A
|
||||||
P 950 4450
|
P 2000 5200
|
||||||
F 0 "#FLG0101" H 950 4525 50 0001 C CNN
|
F 0 "#FLG0101" H 2000 5275 50 0001 C CNN
|
||||||
F 1 "PWR_FLAG" V 950 4578 50 0000 L CNN
|
F 1 "PWR_FLAG" H 1900 5350 50 0000 L CNN
|
||||||
F 2 "" H 950 4450 50 0001 C CNN
|
F 2 "" H 2000 5200 50 0001 C CNN
|
||||||
F 3 "~" H 950 4450 50 0001 C CNN
|
F 3 "~" H 2000 5200 50 0001 C CNN
|
||||||
1 950 4450
|
1 2000 5200
|
||||||
0 1 1 0
|
1 0 0 -1
|
||||||
$EndComp
|
$EndComp
|
||||||
Connection ~ 950 4450
|
|
||||||
Text GLabel 5900 6800 2 50 Input ~ 0
|
Text GLabel 5900 6800 2 50 Input ~ 0
|
||||||
SENSORS_ENABLE
|
SENSORS_ENABLE
|
||||||
$Comp
|
$Comp
|
||||||
@ -2391,44 +2381,31 @@ $EndComp
|
|||||||
Connection ~ 10700 5400
|
Connection ~ 10700 5400
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
10700 5400 10700 5550
|
10700 5400 10700 5550
|
||||||
Wire Wire Line
|
Text GLabel 1650 3600 0 50 Input ~ 0
|
||||||
1000 3500 1550 3500
|
|
||||||
Text GLabel 1550 3800 0 50 Input ~ 0
|
|
||||||
SOLAR_IN
|
SOLAR_IN
|
||||||
Text GLabel 1550 3600 0 50 Input ~ 0
|
|
||||||
GND
|
|
||||||
Text GLabel 1550 3700 0 50 Input ~ 0
|
|
||||||
GND
|
|
||||||
$Comp
|
$Comp
|
||||||
L Connector_Generic:Conn_01x04 J2
|
L Connector_Generic:Conn_01x04 J2
|
||||||
U 1 1 5F7E5709
|
U 1 1 5F7E5709
|
||||||
P 1750 3600
|
P 1850 3400
|
||||||
F 0 "J2" H 1830 3592 50 0000 L CNN
|
F 0 "J2" H 1930 3392 50 0000 L CNN
|
||||||
F 1 "Conn_01x04" H 1830 3501 50 0000 L CNN
|
F 1 "Conn_01x04" H 1930 3301 50 0000 L CNN
|
||||||
F 2 "Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Horizontal" H 1750 3600 50 0001 C CNN
|
F 2 "Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Horizontal" H 1850 3400 50 0001 C CNN
|
||||||
F 3 "~" H 1750 3600 50 0001 C CNN
|
F 3 "~" H 1850 3400 50 0001 C CNN
|
||||||
1 1750 3600
|
1 1850 3400
|
||||||
1 0 0 -1
|
1 0 0 -1
|
||||||
$EndComp
|
$EndComp
|
||||||
Wire Wire Line
|
|
||||||
1000 4100 1100 4100
|
|
||||||
Connection ~ 1000 3800
|
|
||||||
Wire Wire Line
|
|
||||||
1000 3800 1000 3500
|
|
||||||
$Comp
|
$Comp
|
||||||
L Device:Fuse F1
|
L Device:Fuse F1
|
||||||
U 1 1 5F8D8528
|
U 1 1 5F8D8528
|
||||||
P 1000 3950
|
P 1150 3300
|
||||||
F 0 "F1" H 1060 3996 50 0000 L CNN
|
F 0 "F1" V 1200 3250 50 0000 L CNN
|
||||||
F 1 "Fuse" H 1060 3905 50 0000 L CNN
|
F 1 "Fuse" V 1050 3200 50 0000 L CNN
|
||||||
F 2 "Fuse:Fuse_Blade_ATO_directSolder" V 930 3950 50 0001 C CNN
|
F 2 "Fuse:Fuse_Blade_ATO_directSolder" V 1080 3300 50 0001 C CNN
|
||||||
F 3 "~" H 1000 3950 50 0001 C CNN
|
F 3 "~" H 1150 3300 50 0001 C CNN
|
||||||
1 1000 3950
|
1 1150 3300
|
||||||
1 0 0 -1
|
0 1 1 0
|
||||||
$EndComp
|
$EndComp
|
||||||
Wire Wire Line
|
Text GLabel 1250 3450 0 50 Input ~ 0
|
||||||
1000 3800 850 3800
|
|
||||||
Text GLabel 850 3800 0 50 Input ~ 0
|
|
||||||
LIPO+
|
LIPO+
|
||||||
$Comp
|
$Comp
|
||||||
L power:GND #PWR0138
|
L power:GND #PWR0138
|
||||||
@ -2696,29 +2673,29 @@ Text GLabel 8200 4850 1 50 Input ~ 0
|
|||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
8200 4850 8200 4950
|
8200 4850 8200 4950
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2350 2550 2400 2550
|
2500 2550 2550 2550
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2350 2650 2600 2650
|
2500 2650 2750 2650
|
||||||
$Comp
|
$Comp
|
||||||
L Device:D_Schottky D8
|
L Device:D_Schottky D8
|
||||||
U 1 1 5FA219F6
|
U 1 1 5FA219F6
|
||||||
P 2400 2300
|
P 2550 2250
|
||||||
F 0 "D8" V 2446 2221 50 0000 R CNN
|
F 0 "D8" V 2596 2171 50 0000 R CNN
|
||||||
F 1 "BAS40" V 2355 2221 50 0000 R CNN
|
F 1 "BAS40" V 2505 2171 50 0000 R CNN
|
||||||
F 2 "Diode_SMD:D_1206_3216Metric_Pad1.42x1.75mm_HandSolder" H 2400 2300 50 0001 C CNN
|
F 2 "Diode_SMD:D_1206_3216Metric_Pad1.42x1.75mm_HandSolder" H 2550 2250 50 0001 C CNN
|
||||||
F 3 "~" H 2400 2300 50 0001 C CNN
|
F 3 "~" H 2550 2250 50 0001 C CNN
|
||||||
1 2400 2300
|
1 2550 2250
|
||||||
0 1 1 0
|
0 1 1 0
|
||||||
$EndComp
|
$EndComp
|
||||||
$Comp
|
$Comp
|
||||||
L Device:D_Schottky D10
|
L Device:D_Schottky D10
|
||||||
U 1 1 5FA22159
|
U 1 1 5FA22159
|
||||||
P 2600 2300
|
P 2750 2250
|
||||||
F 0 "D10" V 2646 2221 50 0000 R CNN
|
F 0 "D10" V 2796 2171 50 0000 R CNN
|
||||||
F 1 "BAS40" V 2555 2221 50 0000 R CNN
|
F 1 "BAS40" V 2705 2171 50 0000 R CNN
|
||||||
F 2 "Diode_SMD:D_1206_3216Metric_Pad1.42x1.75mm_HandSolder" H 2600 2300 50 0001 C CNN
|
F 2 "Diode_SMD:D_1206_3216Metric_Pad1.42x1.75mm_HandSolder" H 2750 2250 50 0001 C CNN
|
||||||
F 3 "~" H 2600 2300 50 0001 C CNN
|
F 3 "~" H 2750 2250 50 0001 C CNN
|
||||||
1 2600 2300
|
1 2750 2250
|
||||||
0 1 1 0
|
0 1 1 0
|
||||||
$EndComp
|
$EndComp
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
@ -2728,77 +2705,64 @@ Wire Wire Line
|
|||||||
Connection ~ 6200 5800
|
Connection ~ 6200 5800
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
6200 5800 6250 5800
|
6200 5800 6250 5800
|
||||||
Wire Wire Line
|
|
||||||
2850 2750 2350 2750
|
|
||||||
$Comp
|
$Comp
|
||||||
L Device:D_Schottky D9
|
L Device:D_Schottky D9
|
||||||
U 1 1 5FA542CE
|
U 1 1 5FA542CE
|
||||||
P 2400 2950
|
P 2550 2950
|
||||||
F 0 "D9" V 2446 2871 50 0000 R CNN
|
F 0 "D9" V 2596 2871 50 0000 R CNN
|
||||||
F 1 "BAS40" V 2355 2871 50 0000 R CNN
|
F 1 "BAS40" V 2505 2871 50 0000 R CNN
|
||||||
F 2 "Diode_SMD:D_1206_3216Metric_Pad1.42x1.75mm_HandSolder" H 2400 2950 50 0001 C CNN
|
F 2 "Diode_SMD:D_1206_3216Metric_Pad1.42x1.75mm_HandSolder" H 2550 2950 50 0001 C CNN
|
||||||
F 3 "~" H 2400 2950 50 0001 C CNN
|
F 3 "~" H 2550 2950 50 0001 C CNN
|
||||||
1 2400 2950
|
1 2550 2950
|
||||||
0 1 1 0
|
0 1 1 0
|
||||||
$EndComp
|
$EndComp
|
||||||
$Comp
|
$Comp
|
||||||
L Device:D_Schottky D11
|
L Device:D_Schottky D11
|
||||||
U 1 1 5FA54A31
|
U 1 1 5FA54A31
|
||||||
P 2600 2950
|
P 2750 2950
|
||||||
F 0 "D11" V 2646 2871 50 0000 R CNN
|
F 0 "D11" V 2796 2871 50 0000 R CNN
|
||||||
F 1 "BAS40" V 2555 2871 50 0000 R CNN
|
F 1 "BAS40" V 2705 2871 50 0000 R CNN
|
||||||
F 2 "Diode_SMD:D_1206_3216Metric_Pad1.42x1.75mm_HandSolder" H 2600 2950 50 0001 C CNN
|
F 2 "Diode_SMD:D_1206_3216Metric_Pad1.42x1.75mm_HandSolder" H 2750 2950 50 0001 C CNN
|
||||||
F 3 "~" H 2600 2950 50 0001 C CNN
|
F 3 "~" H 2750 2950 50 0001 C CNN
|
||||||
1 2600 2950
|
1 2750 2950
|
||||||
0 1 1 0
|
0 1 1 0
|
||||||
$EndComp
|
$EndComp
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2400 2550 2400 2800
|
2550 2550 2550 2800
|
||||||
Connection ~ 2400 2550
|
Connection ~ 2550 2550
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2400 2550 2850 2550
|
2550 2550 2850 2550
|
||||||
|
Connection ~ 2750 2650
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2400 2450 2400 2550
|
2750 2650 2850 2650
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2600 2450 2600 2650
|
2750 2650 2750 2800
|
||||||
Connection ~ 2600 2650
|
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2600 2650 2850 2650
|
2550 3100 2550 3150
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2600 2650 2600 2800
|
2550 3150 2650 3150
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2400 3100 2400 3150
|
2750 3150 2750 3100
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2400 3150 2500 3150
|
2550 2100 2550 2050
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2600 3150 2600 3100
|
2750 2050 2750 2100
|
||||||
Wire Wire Line
|
|
||||||
2400 2150 2400 2100
|
|
||||||
Wire Wire Line
|
|
||||||
2400 2100 2500 2100
|
|
||||||
Wire Wire Line
|
|
||||||
2600 2100 2600 2150
|
|
||||||
$Comp
|
$Comp
|
||||||
L power:GND #PWR0140
|
L power:GND #PWR0140
|
||||||
U 1 1 5FAD1A1F
|
U 1 1 5FAD1A1F
|
||||||
P 2500 3150
|
P 2650 3150
|
||||||
F 0 "#PWR0140" H 2500 2900 50 0001 C CNN
|
F 0 "#PWR0140" H 2650 2900 50 0001 C CNN
|
||||||
F 1 "GND" V 2505 3022 50 0000 R CNN
|
F 1 "GND" V 2655 3022 50 0000 R CNN
|
||||||
F 2 "" H 2500 3150 50 0001 C CNN
|
F 2 "" H 2650 3150 50 0001 C CNN
|
||||||
F 3 "" H 2500 3150 50 0001 C CNN
|
F 3 "" H 2650 3150 50 0001 C CNN
|
||||||
1 2500 3150
|
1 2650 3150
|
||||||
1 0 0 -1
|
1 0 0 -1
|
||||||
$EndComp
|
$EndComp
|
||||||
Connection ~ 2500 3150
|
Connection ~ 2650 3150
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
2500 3150 2600 3150
|
2650 3150 2750 3150
|
||||||
Text GLabel 2500 2100 1 50 Input ~ 0
|
Text GLabel 2650 2000 1 50 Input ~ 0
|
||||||
3_3V
|
3_3V
|
||||||
Wire Wire Line
|
|
||||||
2500 2050 2500 2100
|
|
||||||
Connection ~ 2500 2100
|
|
||||||
Wire Wire Line
|
|
||||||
2500 2100 2600 2100
|
|
||||||
Text Notes 500 6650 0 105 ~ 0
|
Text Notes 500 6650 0 105 ~ 0
|
||||||
External Fix Power
|
External Fix Power
|
||||||
$Comp
|
$Comp
|
||||||
@ -2861,8 +2825,6 @@ Wire Wire Line
|
|||||||
10150 800 10200 800
|
10150 800 10200 800
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
10200 800 10200 950
|
10200 800 10200 950
|
||||||
Wire Wire Line
|
|
||||||
10200 800 10650 800
|
|
||||||
Wire Wire Line
|
Wire Wire Line
|
||||||
10650 800 10650 950
|
10650 800 10650 950
|
||||||
Connection ~ 10200 800
|
Connection ~ 10200 800
|
||||||
@ -2886,4 +2848,171 @@ Text GLabel 10150 800 0 50 Input ~ 0
|
|||||||
PWR_SENSORS
|
PWR_SENSORS
|
||||||
Text GLabel 10500 2100 2 50 Input ~ 0
|
Text GLabel 10500 2100 2 50 Input ~ 0
|
||||||
PWR_SENSORS
|
PWR_SENSORS
|
||||||
|
$Comp
|
||||||
|
L DW01:DW01 IC1
|
||||||
|
U 1 1 5FB36987
|
||||||
|
P 1100 4200
|
||||||
|
F 0 "IC1" H 1600 4467 50 0000 C CNN
|
||||||
|
F 1 "DW01" H 1600 4376 50 0000 C CNN
|
||||||
|
F 2 "SOT95P280X135-6N" H 1100 4200 50 0001 L BNN
|
||||||
|
F 3 "" H 1100 4200 50 0001 L BNN
|
||||||
|
F 4 "1.35mm" H 1100 4200 50 0001 L BNN "HEIGHT"
|
||||||
|
F 5 "ic" H 1100 4200 50 0001 L BNN "DESCRIPTION"
|
||||||
|
F 6 "" H 1100 4200 50 0001 L BNN "LCSC_PRICE-STOCK"
|
||||||
|
F 7 "DW01" H 1100 4200 50 0001 L BNN "MANUFACTURER_PART_NUMBER"
|
||||||
|
F 8 "" H 1100 4200 50 0001 L BNN "LCSC_PART_NUMBER"
|
||||||
|
F 9 "Slkor" H 1100 4200 50 0001 L BNN "MANUFACTURER_NAME"
|
||||||
|
1 1100 4200
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
$Comp
|
||||||
|
L ESP32-DEVKITC-32D:SL2300 Q12
|
||||||
|
U 1 1 5FB3ECD2
|
||||||
|
P 1750 5250
|
||||||
|
F 0 "Q12" V 2042 5250 50 0000 C CNN
|
||||||
|
F 1 "SL2300" V 1951 5250 50 0000 C CNN
|
||||||
|
F 2 "" H 1750 5250 50 0001 C CNN
|
||||||
|
F 3 "" H 1750 5250 50 0001 C CNN
|
||||||
|
1 1750 5250
|
||||||
|
0 -1 -1 0
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
1550 5200 1400 5200
|
||||||
|
Wire Wire Line
|
||||||
|
1650 3500 1650 3400
|
||||||
|
$Comp
|
||||||
|
L Device:R R52
|
||||||
|
U 1 1 5FC59C43
|
||||||
|
P 950 4300
|
||||||
|
F 0 "R52" V 950 4300 50 0000 C CNN
|
||||||
|
F 1 "1K" V 800 4300 50 0000 C CNN
|
||||||
|
F 2 "" V 880 4300 50 0001 C CNN
|
||||||
|
F 3 "~" H 950 4300 50 0001 C CNN
|
||||||
|
1 950 4300
|
||||||
|
0 -1 -1 0
|
||||||
|
$EndComp
|
||||||
|
$Comp
|
||||||
|
L Device:R R53
|
||||||
|
U 1 1 5FC908BA
|
||||||
|
P 2550 4300
|
||||||
|
F 0 "R53" V 2343 4300 50 0000 C CNN
|
||||||
|
F 1 "100Ohm" V 2434 4300 50 0000 C CNN
|
||||||
|
F 2 "" V 2480 4300 50 0001 C CNN
|
||||||
|
F 3 "~" H 2550 4300 50 0001 C CNN
|
||||||
|
1 2550 4300
|
||||||
|
0 1 1 0
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
1950 5200 2000 5200
|
||||||
|
$Comp
|
||||||
|
L Device:C C10
|
||||||
|
U 1 1 5FCD9EFE
|
||||||
|
P 2250 4150
|
||||||
|
F 0 "C10" H 2365 4196 50 0000 L CNN
|
||||||
|
F 1 "C" H 2365 4105 50 0000 L CNN
|
||||||
|
F 2 "" H 2288 4000 50 0001 C CNN
|
||||||
|
F 3 "~" H 2250 4150 50 0001 C CNN
|
||||||
|
1 2250 4150
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
Text GLabel 1650 3500 0 50 Input ~ 0
|
||||||
|
GND
|
||||||
|
Text GLabel 2100 5200 2 50 Input ~ 0
|
||||||
|
GND
|
||||||
|
Text GLabel 2700 4400 0 50 Input ~ 0
|
||||||
|
GND_BATT
|
||||||
|
Text GLabel 1000 5200 0 50 Input ~ 0
|
||||||
|
GND_BATT
|
||||||
|
Connection ~ 2000 5200
|
||||||
|
Wire Wire Line
|
||||||
|
2000 5200 2100 5200
|
||||||
|
Wire Wire Line
|
||||||
|
2100 4300 2250 4300
|
||||||
|
Text GLabel 2300 4000 2 50 Input ~ 0
|
||||||
|
GND_BATT
|
||||||
|
Text GLabel 800 4300 0 50 Input ~ 0
|
||||||
|
GND
|
||||||
|
Connection ~ 2250 4300
|
||||||
|
Wire Wire Line
|
||||||
|
2250 4300 2400 4300
|
||||||
|
Wire Wire Line
|
||||||
|
2100 4200 2100 4000
|
||||||
|
Wire Wire Line
|
||||||
|
2100 4000 2250 4000
|
||||||
|
Wire Wire Line
|
||||||
|
2250 4000 2300 4000
|
||||||
|
Connection ~ 2250 4000
|
||||||
|
Wire Wire Line
|
||||||
|
2700 4300 2850 4300
|
||||||
|
Wire Wire Line
|
||||||
|
2700 4400 2850 4400
|
||||||
|
Text GLabel 2800 4300 1 50 Input ~ 0
|
||||||
|
VCC_BATT
|
||||||
|
Text GLabel 1000 3300 0 50 Input ~ 0
|
||||||
|
VCC_BATT
|
||||||
|
Wire Wire Line
|
||||||
|
1300 3300 1350 3300
|
||||||
|
Wire Wire Line
|
||||||
|
1350 3450 1250 3450
|
||||||
|
Wire Wire Line
|
||||||
|
1350 3300 1350 3450
|
||||||
|
Connection ~ 1350 3300
|
||||||
|
Wire Wire Line
|
||||||
|
1350 3300 1650 3300
|
||||||
|
Wire Wire Line
|
||||||
|
2850 2750 2500 2750
|
||||||
|
Wire Wire Line
|
||||||
|
2550 2400 2550 2550
|
||||||
|
Wire Wire Line
|
||||||
|
2750 2400 2750 2650
|
||||||
|
Wire Wire Line
|
||||||
|
2850 2450 2500 2450
|
||||||
|
Wire Wire Line
|
||||||
|
2550 2050 2650 2050
|
||||||
|
Wire Wire Line
|
||||||
|
2650 2000 2650 2050
|
||||||
|
Connection ~ 2650 2050
|
||||||
|
Wire Wire Line
|
||||||
|
2650 2050 2750 2050
|
||||||
|
Text GLabel 850 4200 0 50 Input ~ 0
|
||||||
|
LIPO_OD
|
||||||
|
Text GLabel 1200 4850 1 50 Input ~ 0
|
||||||
|
LIPO_OD
|
||||||
|
Text GLabel 850 4400 0 50 Input ~ 0
|
||||||
|
LIPO_OC
|
||||||
|
Wire Wire Line
|
||||||
|
850 4200 1100 4200
|
||||||
|
Wire Wire Line
|
||||||
|
850 4400 1100 4400
|
||||||
|
Text GLabel 1750 5600 3 50 Input ~ 0
|
||||||
|
LIPO_OC
|
||||||
|
Wire Wire Line
|
||||||
|
1750 5600 1750 5500
|
||||||
|
$Comp
|
||||||
|
L ESP32-DEVKITC-32D:SL2300 Q11
|
||||||
|
U 1 1 5FB813FB
|
||||||
|
P 1200 5150
|
||||||
|
F 0 "Q11" V 1399 5150 50 0000 C CNN
|
||||||
|
F 1 "SL2300" V 1490 5150 50 0000 C CNN
|
||||||
|
F 2 "" H 1200 5150 50 0001 C CNN
|
||||||
|
F 3 "" H 1200 5150 50 0001 C CNN
|
||||||
|
1 1200 5150
|
||||||
|
0 1 1 0
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
1200 4850 1200 4900
|
||||||
|
NoConn ~ 2100 4400
|
||||||
|
$Comp
|
||||||
|
L power:PWR_FLAG #FLG0102
|
||||||
|
U 1 1 6013ADBD
|
||||||
|
P 10700 5400
|
||||||
|
F 0 "#FLG0102" H 10700 5475 50 0001 C CNN
|
||||||
|
F 1 "PWR_FLAG" H 10600 5550 50 0000 L CNN
|
||||||
|
F 2 "" H 10700 5400 50 0001 C CNN
|
||||||
|
F 3 "~" H 10700 5400 50 0001 C CNN
|
||||||
|
1 10700 5400
|
||||||
|
0 -1 -1 0
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
10200 800 10650 800
|
||||||
$EndSCHEMATC
|
$EndSCHEMATC
|
||||||
|
@ -2,4 +2,5 @@
|
|||||||
(lib (name LP38690DT-3.3)(type Legacy)(uri ${KIPRJMOD}/kicad-stuff/LP38690DT-3.3.lib)(options "")(descr ""))
|
(lib (name LP38690DT-3.3)(type Legacy)(uri ${KIPRJMOD}/kicad-stuff/LP38690DT-3.3.lib)(options "")(descr ""))
|
||||||
(lib (name ESP32-DEVKITC-32D)(type Legacy)(uri ${KIPRJMOD}/kicad-stuff/ESP32/ESP32-DEVKITC-32D.lib)(options "")(descr ""))
|
(lib (name ESP32-DEVKITC-32D)(type Legacy)(uri ${KIPRJMOD}/kicad-stuff/ESP32/ESP32-DEVKITC-32D.lib)(options "")(descr ""))
|
||||||
(lib (name PlantCtrlESP32-rescue)(type Legacy)(uri ${KIPRJMOD}/PlantCtrlESP32-rescue.lib)(options "")(descr ""))
|
(lib (name PlantCtrlESP32-rescue)(type Legacy)(uri ${KIPRJMOD}/PlantCtrlESP32-rescue.lib)(options "")(descr ""))
|
||||||
|
(lib (name DW01)(type Legacy)(uri ${KIPRJMOD}/kicad-stuff/DW01.lib)(options "")(descr ""))
|
||||||
)
|
)
|
||||||
|
1
esp32/.gitignore
vendored
1
esp32/.gitignore
vendored
@ -3,3 +3,4 @@
|
|||||||
.vscode/c_cpp_properties.json
|
.vscode/c_cpp_properties.json
|
||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
.vscode/ipch
|
.vscode/ipch
|
||||||
|
doc/
|
||||||
|
2522
esp32/Doxyfile
Normal file
2522
esp32/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,23 @@ Uses ESP32MiniKit
|
|||||||
* Temperature
|
* Temperature
|
||||||
* Custom GPIO
|
* Custom GPIO
|
||||||
|
|
||||||
|
## Documentation of Power-Modes
|
||||||
|
https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/#esp32-deep-sleep
|
||||||
|
|
||||||
|
|
||||||
|
gpio 17 only out no hold
|
||||||
|
gpio 16 only out no hold
|
||||||
|
|
||||||
|
## Additional hardware
|
||||||
|
solar charger 2A?
|
||||||
|
https://www.aliexpress.com/item/4000238259949.html?spm=a2g0o.productlist.0.0.7e50231cCWGu0Z&algo_pvid=9ab7b0d3-5026-438b-972b-1d4a81d4dc56&algo_expid=9ab7b0d3-5026-438b-972b-1d4a81d4dc56-11&btsid=0b0a0ac215999246489888249e72a9&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_
|
||||||
|
|
||||||
|
MT3608 boost für pumpe
|
||||||
|
https://www.aliexpress.com/item/32925951391.html?spm=a2g0o.productlist.0.0.39e21087nAzH9q&algo_pvid=7db0a849-62f7-4403-88e3-615ee4d99339&algo_expid=7db0a849-62f7-4403-88e3-615ee4d99339-0&btsid=0b0a0ac215999252934777876e7253&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_
|
||||||
|
|
||||||
|
DS18B20 one wire temp sensor
|
||||||
|
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
## Empires Wunschliste
|
## Empires Wunschliste
|
||||||
* Pflanze
|
* Pflanze
|
||||||
|
@ -12,7 +12,6 @@ For further details have a look at the Readme.md one level above.
|
|||||||
|
|
||||||
# Remote Upload
|
# Remote Upload
|
||||||
|
|
||||||
|
|
||||||
This script will allow you to send an OTA update to your device.
|
This script will allow you to send an OTA update to your device.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
@ -22,6 +21,12 @@ Requirements are:
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
See ***upload-via-mqtt.sh***
|
||||||
|
|
||||||
|
# Remote Upload - Backend
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
```text
|
```text
|
||||||
usage: ota_updater.py [-h] -l BROKER_HOST -p BROKER_PORT [-u BROKER_USERNAME]
|
usage: ota_updater.py [-h] -l BROKER_HOST -p BROKER_PORT [-u BROKER_USERNAME]
|
||||||
[-d BROKER_PASSWORD] [-t BASE_TOPIC] -i DEVICE_ID
|
[-d BROKER_PASSWORD] [-t BASE_TOPIC] -i DEVICE_ID
|
||||||
|
27
esp32/host/upload-via-mqtt.sh
Executable file
27
esp32/host/upload-via-mqtt.sh
Executable file
@ -0,0 +1,27 @@
|
|||||||
|
#!//bin/bash
|
||||||
|
|
||||||
|
if [ $# -ne 3 ]; then
|
||||||
|
echo "Homie prefex and device index must be specified:"
|
||||||
|
echo "$0 <mqtt host> <prefix> <device index>"
|
||||||
|
echo "e.g."
|
||||||
|
echo "$0 192.168.0.2 test/ MyDeviceId"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mqttHost=$1
|
||||||
|
mqttPrefix=$2
|
||||||
|
homieId=$3
|
||||||
|
firmwareFile=../.pio/build/esp32doit-devkit-v1/firmware.bin
|
||||||
|
|
||||||
|
if [ ! -f $firmwareFile ]; then
|
||||||
|
echo "the script $0 must be started in host/ sub directory"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
mosquitto_pub -h $mqttHost -t "${mqttPrefix}${homieId}/stay/alive/set" -m "1" -r
|
||||||
|
echo "Waiting ..."
|
||||||
|
mosquitto_sub -h $mqttHost -t "${mqttPrefix}${homieId}/#" -R -C 1
|
||||||
|
python ota_updater.py -l $mqttHost -t "$mqttPrefix" -i "$homieId" $firmwareFile
|
||||||
|
|
||||||
|
mosquitto_pub -h $mqttHost -t "${mqttPrefix}${homieId}/stay/alive/set" -m "0" -r
|
||||||
|
exit 0
|
@ -6,18 +6,55 @@
|
|||||||
* @date 2020-05-30
|
* @date 2020-05-30
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2020
|
* @copyright Copyright (c) 2020
|
||||||
|
*
|
||||||
|
* \mainpage Configuration of the controller
|
||||||
|
* @{
|
||||||
* Describe the used PINs of the controller
|
* Describe the used PINs of the controller
|
||||||
|
*
|
||||||
|
* @subpage Controller
|
||||||
|
*
|
||||||
|
* @subpage Homie
|
||||||
|
*
|
||||||
|
* @subpage Configuration
|
||||||
|
*
|
||||||
|
* There are several modes in the controller
|
||||||
|
* \dot
|
||||||
|
* digraph Operationmode {
|
||||||
|
* ranksep=.75;
|
||||||
|
* poweroff [ label="off" ];
|
||||||
|
* mode1 [ label="Mode 1 - Sensor only", shape=box, width=2 ];
|
||||||
|
* mode2 [ label="Mode 2 - Wifi enabled", shape=box ];
|
||||||
|
* mode3 [ label="Mode 3 - Stay alive", shape=box ];
|
||||||
|
* mode1 -> mode2 [ label="wakeup reason", fontsize=10 ];
|
||||||
|
* mode1 -> mode2 [ label="Time duration", fontsize=10 ];
|
||||||
|
* mode2 -> mode3 [ label="Over the Air Update", fontsize=10 ];
|
||||||
|
* mode3 -> mode2 [ label="Over the Air Finished", fontsize=10 ];
|
||||||
|
* mode3 -> mode2 [ label="Mqtt Command", fontsize=10 ];
|
||||||
|
* mode2 -> mode3 [ label="Mqtt Command", fontsize=10 ];
|
||||||
|
* poweroff -> mode1 [ label="deep sleep wakeup", fontsize=10 ];
|
||||||
|
* mode1 -> poweroff [ label="enter deep sleep", fontsize=10 ];
|
||||||
|
* mode2 -> poweroff [ label="Mqtt queue empty", fontsize=10 ];
|
||||||
|
* }
|
||||||
|
* \enddot
|
||||||
|
*
|
||||||
|
* Before entering Deep sleep the controller is configured with an wakeup time.
|
||||||
|
*
|
||||||
|
* @}
|
||||||
*/
|
*/
|
||||||
#ifndef CONTROLLER_CONFIG_H
|
#ifndef CONTROLLER_CONFIG_H
|
||||||
#define CONTROLLER_CONFIG_H
|
#define CONTROLLER_CONFIG_H
|
||||||
|
/** \addtogroup Configuration
|
||||||
#define FIRMWARE_VERSION "1.0.6"
|
* @{
|
||||||
|
*/
|
||||||
|
#define FIRMWARE_VERSION "1.0.9"
|
||||||
|
|
||||||
#define ADC_TO_VOLT(adc) ((adc) * 3.3 ) / 4095)
|
#define ADC_TO_VOLT(adc) ((adc) * 3.3 ) / 4095)
|
||||||
#define ADC_TO_VOLT_WITH_MULTI(adc, multi) (((adc)*3.3 * (multi)) / 4095)
|
#define ADC_TO_VOLT_WITH_MULTI(adc, multi) (((adc)*3.3 * (multi)) / 4095)
|
||||||
|
#define MOIST_SENSOR_MAX_ADC (85 * 4095 / 100)
|
||||||
|
#define MOIST_SENSOR_MIN_ADC (25 * 4095 / 100)
|
||||||
|
|
||||||
#define SOLAR_VOLT(adc) ADC_TO_VOLT_WITH_MULTI(adc, 4.0306) /**< 100k and 33k voltage dividor */
|
#define SOLAR_VOLT(adc) ADC_TO_VOLT_WITH_MULTI(adc, 4.0306) /**< 100k and 33k voltage dividor */
|
||||||
#define ADC_5V_TO_3V3(adc) ADC_TO_VOLT_WITH_MULTI(adc, 1.7) /**< 33k and 47k8 voltage dividor */
|
#define ADC_5V_TO_3V3(adc) ADC_TO_VOLT_WITH_MULTI(adc, 1.69) /**< 33k and 47k8 voltage dividor */
|
||||||
#define MS_TO_S 1000
|
#define MS_TO_S 1000
|
||||||
|
|
||||||
#define SENSOR_LIPO 34 /**< GPIO 34 (ADC1) */
|
#define SENSOR_LIPO 34 /**< GPIO 34 (ADC1) */
|
||||||
@ -41,16 +78,16 @@
|
|||||||
#define OUTPUT_SENSOR 16 /**< GPIO 16 - Enable Sensors */
|
#define OUTPUT_SENSOR 16 /**< GPIO 16 - Enable Sensors */
|
||||||
#define OUTPUT_PUMP 13 /**< GPIO 13 - Enable Pumps */
|
#define OUTPUT_PUMP 13 /**< GPIO 13 - Enable Pumps */
|
||||||
|
|
||||||
#define SENSOR_DS18B20 2 /**< GPIO 2 */
|
#define SENSOR_DS18B20 2 /**< GPIO 2 - Temperatur sensor */
|
||||||
#define BUTTON 0 /**< GPIO 0 */
|
#define BUTTON 0 /**< GPIO 0 - Fix button of NodeMCU */
|
||||||
|
|
||||||
#define MIN_TIME_RUNNING 5UL /**< Amount of seconds the controller must stay awoken */
|
#define MIN_TIME_RUNNING 5UL /**< Amount of seconds the controller must stay awoken */
|
||||||
#define MAX_PLANTS 7
|
#define MAX_PLANTS 7
|
||||||
#define MINIMUM_LIPO_VOLT 3.6f /**< Minimum voltage of the Lipo, that must be present */
|
#define MINIMUM_LIPO_VOLT 3.6f /**< Minimum voltage of the Lipo, that must be present */
|
||||||
#define NO_LIPO_VOLT 2.0f /**< No Lipo connected */
|
#define NO_LIPO_VOLT 2.0f /**< No Lipo connected */
|
||||||
#define MINIMUM_SOLAR_VOLT 4.0f /**< Minimum voltage of the sun, to detect daylight */
|
#define MINIMUM_SOLAR_VOLT 4.0f /**< Minimum voltage of the sun, to detect daylight */
|
||||||
#define SOLAR_CHARGE_MIN_VOLTAGE 7
|
#define SOLAR_CHARGE_MIN_VOLTAGE 7 /**< Sun is rising (morning detected) */
|
||||||
#define SOLAR_CHARGE_MAX_VOLTAGE 9
|
#define SOLAR_CHARGE_MAX_VOLTAGE 9 /**< Sun is shining (noon) */
|
||||||
|
|
||||||
#define HC_SR04 /**< Ultrasonic distance sensor to measure water level */
|
#define HC_SR04 /**< Ultrasonic distance sensor to measure water level */
|
||||||
#define SENSOR_SR04_ECHO 17 /**< GPIO 17 - Echo */
|
#define SENSOR_SR04_ECHO 17 /**< GPIO 17 - Echo */
|
||||||
@ -61,4 +98,10 @@
|
|||||||
#define PANIK_MODE_DEEPSLEEP (60 * 60 * 5U) /**< 5 hours in usecond */
|
#define PANIK_MODE_DEEPSLEEP (60 * 60 * 5U) /**< 5 hours in usecond */
|
||||||
#define PANIK_MODE_DEEPSLEEP_US (PANIK_MODE_DEEPSLEEP * 1000 * 1000)
|
#define PANIK_MODE_DEEPSLEEP_US (PANIK_MODE_DEEPSLEEP * 1000 * 1000)
|
||||||
|
|
||||||
|
#define TEMPERATURE_DELTA_TRIGGER_IN_C 1.0f
|
||||||
|
#define MOIST_DELTA_TRIGGER_ADC 10
|
||||||
|
#define SOLAR_DELTA_VOLT_ADC 3
|
||||||
|
#define LIPO_DELTA_VOLT_ADC 0.2 /**< trigger for lipo voltage */
|
||||||
|
|
||||||
|
/* @} */
|
||||||
#endif
|
#endif
|
@ -21,16 +21,20 @@
|
|||||||
|
|
||||||
#include <OneWire.h>
|
#include <OneWire.h>
|
||||||
|
|
||||||
class Ds18B20 {
|
class Ds18B20
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
OneWire *mDs;
|
OneWire *mDs;
|
||||||
int foundDevices;
|
int foundDevices;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Ds18B20(int pin) {
|
Ds18B20(int pin)
|
||||||
|
{
|
||||||
this->mDs = new OneWire(pin);
|
this->mDs = new OneWire(pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Ds18B20() {
|
~Ds18B20()
|
||||||
|
{
|
||||||
delete this->mDs;
|
delete this->mDs;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
/**
|
/** \addtogroup Homie
|
||||||
|
* @{
|
||||||
|
*
|
||||||
* @file HomieConfiguration.h
|
* @file HomieConfiguration.h
|
||||||
* @author your name (you@domain.com)
|
* @author your name (you@domain.com)
|
||||||
* @brief
|
* @brief
|
||||||
@ -7,6 +9,7 @@
|
|||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2020
|
* @copyright Copyright (c) 2020
|
||||||
* All Settings, configurable in Homie
|
* All Settings, configurable in Homie
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
#ifndef HOMIE_PLANT_CONFIG_H
|
#ifndef HOMIE_PLANT_CONFIG_H
|
||||||
#define HOMIE_PLANT_CONFIG_H
|
#define HOMIE_PLANT_CONFIG_H
|
||||||
@ -16,37 +19,52 @@
|
|||||||
#define MAX_PLANTS 7
|
#define MAX_PLANTS 7
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*********************************** Attributes *******************************
|
* @name Attributes
|
||||||
*/
|
* generated Information
|
||||||
|
* @{
|
||||||
|
**/
|
||||||
|
|
||||||
HomieNode plant0("plant0", "Plant 0", "Plant");
|
HomieNode plant0("plant0", "Plant 0", "Plant"); /**< dynamic Homie information for first plant */
|
||||||
|
HomieNode plant1("plant1", "Plant 1", "Plant"); /**< dynamic Homie information for second plant */
|
||||||
HomieNode plant1("plant1", "Plant 1", "Plant");
|
HomieNode plant2("plant2", "Plant 2", "Plant"); /**< dynamic Homie information for first plant */
|
||||||
HomieNode plant2("plant2", "Plant 2", "Plant");
|
HomieNode plant3("plant3", "Plant 3", "Plant"); /**< dynamic Homie information for first plant */
|
||||||
HomieNode plant3("plant3", "Plant 3", "Plant");
|
HomieNode plant4("plant4", "Plant 4", "Plant"); /**< dynamic Homie information for first plant */
|
||||||
HomieNode plant4("plant4", "Plant 4", "Plant");
|
HomieNode plant5("plant5", "Plant 5", "Plant"); /**< dynamic Homie information for first plant */
|
||||||
HomieNode plant5("plant5", "Plant 5", "Plant");
|
HomieNode plant6("plant6", "Plant 6", "Plant"); /**< dynamic Homie information for first plant */
|
||||||
HomieNode plant6("plant6", "Plant 6", "Plant");
|
|
||||||
|
|
||||||
HomieNode sensorLipo("lipo", "Battery Status", "Lipo");
|
HomieNode sensorLipo("lipo", "Battery Status", "Lipo");
|
||||||
HomieNode sensorSolar("solar", "Solar Status", "Solarpanel");
|
HomieNode sensorSolar("solar", "Solar Status", "Solarpanel");
|
||||||
HomieNode sensorWater("water", "WaterSensor", "Water");
|
HomieNode sensorWater("water", "WaterSensor", "Water");
|
||||||
HomieNode sensorTemp("temperature", "Temperature", "temperature");
|
HomieNode sensorTemp("temperature", "Temperature", "temperature");
|
||||||
HomieNode stayAlive("stay", "alive", "alive");
|
HomieNode stayAlive("stay", "alive", "alive"); /**< Necessary for Mqtt Active Command */
|
||||||
|
|
||||||
|
/* @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*********************************** Settings *******************************
|
* @name Settings
|
||||||
|
* General settings for the controller
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
HomieSetting<long> deepSleepTime("deepsleep", "time in milliseconds to sleep (0 deactivats it)");
|
HomieSetting<long> maxTimeBetweenMQTTUpdates("mqttSleep", "time in seconds to start into mode2");
|
||||||
HomieSetting<long> deepSleepNightTime("nightsleep", "time in milliseconds to sleep (0 uses same setting: deepsleep at night, too)");
|
HomieSetting<long> deepSleepTime("deepsleep", "time in seconds to sleep (0 deactivats it)");
|
||||||
|
HomieSetting<long> deepSleepNightTime("nightsleep", "time in seconds to sleep (0 uses same setting: deepsleep at night, too)");
|
||||||
HomieSetting<long> wateringDeepSleep("pumpdeepsleep", "time seconds to sleep, while a pump is running");
|
HomieSetting<long> wateringDeepSleep("pumpdeepsleep", "time seconds to sleep, while a pump is running");
|
||||||
|
|
||||||
HomieSetting<long> waterLevelMax("watermaxlevel", "distance (mm) at maximum water level");
|
HomieSetting<long> waterLevelMax("watermaxlevel", "distance (mm) at maximum water level");
|
||||||
HomieSetting<long> waterLevelMin("waterminlevel", "distance (mm) at minimum water level (pumps still covered)");
|
HomieSetting<long> waterLevelMin("waterminlevel", "distance (mm) at minimum water level (pumps still covered)");
|
||||||
HomieSetting<long> waterLevelWarn("waterlevelwarn", "warn (mm) if below this water level %");
|
HomieSetting<long> waterLevelWarn("waterlevelwarn", "warn (mm) if below this water level %");
|
||||||
HomieSetting<long> waterLevelVol("waterVolume", "(ml) between minimum and maximum");
|
HomieSetting<long> waterLevelVol("waterVolume", "(ml) between minimum and maximum");
|
||||||
|
HomieSetting<const char *> ntpServer("ntpServer", "NTP server (pool.ntp.org as default)");
|
||||||
|
|
||||||
/** Plant specific ones */
|
/**
|
||||||
|
*@}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Plant specific ones
|
||||||
|
* Setting for one plant
|
||||||
|
* @{
|
||||||
|
**/
|
||||||
|
|
||||||
#define GENERATE_PLANT(plant, strplant) \
|
#define GENERATE_PLANT(plant, strplant) \
|
||||||
HomieSetting<long> mSensorDry##plant = HomieSetting<long>("moistdry" strplant, "Plant " strplant "- Moist sensor dry threshold"); \
|
HomieSetting<long> mSensorDry##plant = HomieSetting<long>("moistdry" strplant, "Plant " strplant "- Moist sensor dry threshold"); \
|
||||||
@ -54,16 +72,22 @@ HomieSetting<long> waterLevelVol("waterVolume", "(ml) between minimum and maximu
|
|||||||
HomieSetting<long> mPumpAllowedHourRangeEnd##plant = HomieSetting<long>("rangehourend" strplant, "Plant" strplant " - Range pump allowed hour end (0-23)"); \
|
HomieSetting<long> mPumpAllowedHourRangeEnd##plant = HomieSetting<long>("rangehourend" strplant, "Plant" strplant " - Range pump allowed hour end (0-23)"); \
|
||||||
HomieSetting<bool> mPumpOnlyWhenLowLight##plant = HomieSetting<bool>("onlyWhenLowLightZ" strplant, "Plant" strplant " - Enable the Pump only, when there is light but not enought to charge battery"); \
|
HomieSetting<bool> mPumpOnlyWhenLowLight##plant = HomieSetting<bool>("onlyWhenLowLightZ" strplant, "Plant" strplant " - Enable the Pump only, when there is light but not enought to charge battery"); \
|
||||||
HomieSetting<long> mPumpCooldownInHours##plant = HomieSetting<long>("cooldownpump" strplant, "Plant" strplant " - How long to wait until the pump is activated again (minutes)"); \
|
HomieSetting<long> mPumpCooldownInHours##plant = HomieSetting<long>("cooldownpump" strplant, "Plant" strplant " - How long to wait until the pump is activated again (minutes)"); \
|
||||||
PlantSettings_t mSetting##plant = { &mSensorDry##plant, &mPumpAllowedHourRangeStart##plant, &mPumpAllowedHourRangeEnd##plant, &mPumpOnlyWhenLowLight##plant, &mPumpCooldownInHours##plant };
|
PlantSettings_t mSetting##plant = {&mSensorDry##plant, &mPumpAllowedHourRangeStart##plant, &mPumpAllowedHourRangeEnd##plant, &mPumpOnlyWhenLowLight##plant, &mPumpCooldownInHours##plant}; \
|
||||||
|
/**< Generate all settings for one plant
|
||||||
|
*
|
||||||
|
* Feature to start pumping only at morning: @link{SOLAR_CHARGE_MIN_VOLTAGE} and @link{SOLAR_CHARGE_MAX_VOLTAGE}
|
||||||
|
*/
|
||||||
|
|
||||||
GENERATE_PLANT(0, "0");
|
/**
|
||||||
GENERATE_PLANT(1, "1");
|
* @}
|
||||||
GENERATE_PLANT(2, "2");
|
*/
|
||||||
GENERATE_PLANT(3, "3");
|
|
||||||
GENERATE_PLANT(4, "4");
|
|
||||||
GENERATE_PLANT(5, "5");
|
|
||||||
GENERATE_PLANT(6, "6");
|
|
||||||
|
|
||||||
|
GENERATE_PLANT(0, "0"); /**< Homie settings for first plant */
|
||||||
|
GENERATE_PLANT(1, "1"); /**< Homie settings for second Plant */
|
||||||
|
GENERATE_PLANT(2, "2"); /**< Homie settings for third plant */
|
||||||
|
GENERATE_PLANT(3, "3"); /**< Homie settings for fourth plant */
|
||||||
|
GENERATE_PLANT(4, "4"); /**< Homie settings for fifth plant */
|
||||||
|
GENERATE_PLANT(5, "5"); /**< Homie settings for sixth plant */
|
||||||
|
GENERATE_PLANT(6, "6"); /**< Homie settings for seventh plant */
|
||||||
|
|
||||||
|
#endif /* HOMIE_PLANT_CONFIG_H @} */
|
||||||
#endif /* HOMIE_PLANT_CONFIG_H */
|
|
@ -14,8 +14,10 @@
|
|||||||
#include <Homie.h>
|
#include <Homie.h>
|
||||||
|
|
||||||
#define DEACTIVATED_PLANT 5000
|
#define DEACTIVATED_PLANT 5000
|
||||||
|
#define MISSING_SENSOR 5001
|
||||||
|
|
||||||
typedef struct PlantSettings_t {
|
typedef struct PlantSettings_t
|
||||||
|
{
|
||||||
HomieSetting<long> *pSensorDry;
|
HomieSetting<long> *pSensorDry;
|
||||||
HomieSetting<long> *pPumpAllowedHourRangeStart;
|
HomieSetting<long> *pPumpAllowedHourRangeStart;
|
||||||
HomieSetting<long> *pPumpAllowedHourRangeEnd;
|
HomieSetting<long> *pPumpAllowedHourRangeEnd;
|
||||||
|
@ -15,17 +15,18 @@
|
|||||||
#include "HomieTypes.h"
|
#include "HomieTypes.h"
|
||||||
#include "RunningMedian.h"
|
#include "RunningMedian.h"
|
||||||
|
|
||||||
class Plant {
|
class Plant
|
||||||
|
{
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RunningMedian moistureRaw = RunningMedian(5);
|
RunningMedian moistureRaw = RunningMedian(5);
|
||||||
HomieNode *mPlant = NULL;
|
HomieNode *mPlant = NULL;
|
||||||
int mPinSensor = 0; /**< Pin of the moist sensor */
|
int mPinSensor = 0; /**< Pin of the moist sensor */
|
||||||
int mPinPump = 0; /**< Pin of the pump */
|
int mPinPump = 0; /**< Pin of the pump */
|
||||||
PlantSettings_t* mSetting;
|
|
||||||
bool mConnected = false;
|
bool mConnected = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
PlantSettings_t *mSetting;
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new Plant object
|
* @brief Construct a new Plant object
|
||||||
*
|
*
|
||||||
@ -47,8 +48,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void addSenseValue(void);
|
void addSenseValue(void);
|
||||||
|
|
||||||
int getSensorValue() { return moistureRaw.getMedian(); }
|
|
||||||
|
|
||||||
void deactivatePump(void);
|
void deactivatePump(void);
|
||||||
|
|
||||||
void activatePump(void);
|
void activatePump(void);
|
||||||
@ -59,13 +58,39 @@ public:
|
|||||||
* @return true
|
* @return true
|
||||||
* @return false
|
* @return false
|
||||||
*/
|
*/
|
||||||
bool isPumpRequired() {
|
bool isPumpRequired()
|
||||||
return (this->mSetting->pSensorDry != NULL)
|
{
|
||||||
&& (this->moistureRaw.getMedian() > this->mSetting->pSensorDry->get())
|
bool isDry = getCurrentMoisture() > getSettingsMoisture();
|
||||||
&& (this->mSetting->pSensorDry->get() != DEACTIVATED_PLANT);
|
bool isActive = isPumpTriggerActive();
|
||||||
|
return isDry && isActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
HomieInternals::SendingPromise& setProperty(const String& property) const {
|
bool isPumpTriggerActive()
|
||||||
|
{
|
||||||
|
return this->mSetting->pSensorDry->get() != DEACTIVATED_PLANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getCurrentMoisture()
|
||||||
|
{
|
||||||
|
if(moistureRaw.getCount()==0){
|
||||||
|
return MISSING_SENSOR;
|
||||||
|
}
|
||||||
|
return this->moistureRaw.getMedian();
|
||||||
|
}
|
||||||
|
long getSettingsMoisture()
|
||||||
|
{
|
||||||
|
if (this->mSetting->pSensorDry != NULL)
|
||||||
|
{
|
||||||
|
return this->mSetting->pSensorDry->get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return DEACTIVATED_PLANT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HomieInternals::SendingPromise &setProperty(const String &property) const
|
||||||
|
{
|
||||||
return mPlant->setProperty(property);
|
return mPlant->setProperty(property);
|
||||||
}
|
}
|
||||||
bool switchHandler(const HomieRange &range, const String &value);
|
bool switchHandler(const HomieRange &range, const String &value);
|
||||||
@ -76,16 +101,23 @@ public:
|
|||||||
* @brief determine, if the plant was recently casted
|
* @brief determine, if the plant was recently casted
|
||||||
* @param sinceLastActivation timestamp of last time
|
* @param sinceLastActivation timestamp of last time
|
||||||
*/
|
*/
|
||||||
bool isInCooldown(long sinceLastActivation) {
|
bool isInCooldown(long sinceLastActivation)
|
||||||
|
{
|
||||||
/* if the time difference is greater than one month, we know these are initial values */
|
/* if the time difference is greater than one month, we know these are initial values */
|
||||||
if (sinceLastActivation > (60 * 60 * 24 * 30)) {
|
if (sinceLastActivation > (60 * 60 * 24 * 30))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (this->mSetting->pPumpCooldownInHours->get() > sinceLastActivation / 3600);
|
return (getCooldownInSeconds() > sinceLastActivation);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAllowedOnlyAtLowLight(void) {
|
long getCooldownInSeconds(){
|
||||||
|
return this->mSetting->pPumpCooldownInHours->get()*60*60;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isAllowedOnlyAtLowLight(void)
|
||||||
|
{
|
||||||
return this->mSetting->pPumpOnlyWhenLowLight->get();
|
return this->mSetting->pPumpOnlyWhenLowLight->get();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -17,14 +17,12 @@
|
|||||||
// not tested ==> use at own risk :)
|
// not tested ==> use at own risk :)
|
||||||
// #define RUNNING_MEDIAN_USE_MALLOC
|
// #define RUNNING_MEDIAN_USE_MALLOC
|
||||||
|
|
||||||
|
|
||||||
// should at least be 5 to be practical,
|
// should at least be 5 to be practical,
|
||||||
// odd sizes results in a 'real' middle element and will be a bit faster.
|
// odd sizes results in a 'real' middle element and will be a bit faster.
|
||||||
// even sizes takes the average of the two middle elements as median
|
// even sizes takes the average of the two middle elements as median
|
||||||
#define MEDIAN_MIN_SIZE 5
|
#define MEDIAN_MIN_SIZE 5
|
||||||
#define MEDIAN_MAX_SIZE 19
|
#define MEDIAN_MAX_SIZE 19
|
||||||
|
|
||||||
|
|
||||||
class RunningMedian
|
class RunningMedian
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -58,7 +56,6 @@ public:
|
|||||||
// returns current used elements, getCount() <= getSize()
|
// returns current used elements, getCount() <= getSize()
|
||||||
uint8_t getCount() { return _cnt; };
|
uint8_t getCount() { return _cnt; };
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
boolean _sorted;
|
boolean _sorted;
|
||||||
uint8_t _size;
|
uint8_t _size;
|
||||||
|
@ -1,202 +0,0 @@
|
|||||||
/**
|
|
||||||
arduino-timer - library for delaying function calls
|
|
||||||
|
|
||||||
Copyright (c) 2018, Michael Contreras
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
||||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
||||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _CM_ARDUINO_TIMER_H__
|
|
||||||
#define _CM_ARDUINO_TIMER_H__
|
|
||||||
|
|
||||||
#if defined(ARDUINO) && ARDUINO >= 100
|
|
||||||
#include <Arduino.h>
|
|
||||||
#else
|
|
||||||
#include <WProgram.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef TIMER_MAX_TASKS
|
|
||||||
#define TIMER_MAX_TASKS 0x10
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <
|
|
||||||
size_t max_tasks = TIMER_MAX_TASKS, /* max allocated tasks */
|
|
||||||
unsigned long (*time_func)() = millis, /* time function for timer */
|
|
||||||
typename T = void * /* handler argument type */
|
|
||||||
>
|
|
||||||
class Timer {
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef uintptr_t Task; /* public task handle */
|
|
||||||
typedef bool (*handler_t)(T opaque); /* task handler func signature */
|
|
||||||
|
|
||||||
/* Calls handler with opaque as argument in delay units of time */
|
|
||||||
Task
|
|
||||||
in(unsigned long delay, handler_t h, T opaque = T())
|
|
||||||
{
|
|
||||||
return task_id(add_task(time_func(), delay, h, opaque));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calls handler with opaque as argument at time */
|
|
||||||
Task
|
|
||||||
at(unsigned long time, handler_t h, T opaque = T())
|
|
||||||
{
|
|
||||||
const unsigned long now = time_func();
|
|
||||||
return task_id(add_task(now, time - now, h, opaque));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calls handler with opaque as argument every interval units of time */
|
|
||||||
Task
|
|
||||||
every(unsigned long interval, handler_t h, T opaque = T())
|
|
||||||
{
|
|
||||||
return task_id(add_task(time_func(), interval, h, opaque, interval));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cancel the timer task */
|
|
||||||
void
|
|
||||||
cancel(Task &task)
|
|
||||||
{
|
|
||||||
if (!task) return;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < max_tasks; ++i) {
|
|
||||||
struct task * const t = &tasks[i];
|
|
||||||
|
|
||||||
if (t->handler && (t->id ^ task) == (uintptr_t)t) {
|
|
||||||
remove(t);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task = (Task)NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ticks the timer forward - call this function in loop() */
|
|
||||||
unsigned long
|
|
||||||
tick()
|
|
||||||
{
|
|
||||||
unsigned long ticks = (unsigned long)-1;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < max_tasks; ++i) {
|
|
||||||
struct task * const task = &tasks[i];
|
|
||||||
|
|
||||||
if (task->handler) {
|
|
||||||
const unsigned long t = time_func();
|
|
||||||
const unsigned long duration = t - task->start;
|
|
||||||
|
|
||||||
if (duration >= task->expires) {
|
|
||||||
task->repeat = task->handler(task->opaque) && task->repeat;
|
|
||||||
|
|
||||||
if (task->repeat) task->start = t;
|
|
||||||
else remove(task);
|
|
||||||
} else {
|
|
||||||
const unsigned long remaining = task->expires - duration;
|
|
||||||
ticks = remaining < ticks ? remaining : ticks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ticks == (unsigned long)-1 ? 0 : ticks;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
size_t ctr;
|
|
||||||
|
|
||||||
struct task {
|
|
||||||
handler_t handler; /* task handler callback func */
|
|
||||||
T opaque; /* argument given to the callback handler */
|
|
||||||
unsigned long start,
|
|
||||||
expires; /* when the task expires */
|
|
||||||
size_t repeat, /* repeat task */
|
|
||||||
id;
|
|
||||||
} tasks[max_tasks];
|
|
||||||
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
remove(struct task *task)
|
|
||||||
{
|
|
||||||
task->handler = NULL;
|
|
||||||
task->opaque = T();
|
|
||||||
task->start = 0;
|
|
||||||
task->expires = 0;
|
|
||||||
task->repeat = 0;
|
|
||||||
task->id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
Task
|
|
||||||
task_id(const struct task * const t)
|
|
||||||
{
|
|
||||||
const Task id = (Task)t;
|
|
||||||
|
|
||||||
return id ? id ^ t->id : id;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
struct task *
|
|
||||||
next_task_slot()
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < max_tasks; ++i) {
|
|
||||||
struct task * const slot = &tasks[i];
|
|
||||||
if (slot->handler == NULL) return slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
struct task *
|
|
||||||
add_task(unsigned long start, unsigned long expires,
|
|
||||||
handler_t h, T opaque, bool repeat = 0)
|
|
||||||
{
|
|
||||||
struct task * const slot = next_task_slot();
|
|
||||||
|
|
||||||
if (!slot) return NULL;
|
|
||||||
|
|
||||||
if (++ctr == 0) ++ctr; // overflow
|
|
||||||
|
|
||||||
slot->id = ctr;
|
|
||||||
slot->handler = h;
|
|
||||||
slot->opaque = opaque;
|
|
||||||
slot->start = start;
|
|
||||||
slot->expires = expires;
|
|
||||||
slot->repeat = repeat;
|
|
||||||
|
|
||||||
return slot;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* create a timer with the default settings */
|
|
||||||
inline Timer<>
|
|
||||||
timer_create_default()
|
|
||||||
{
|
|
||||||
return Timer<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -15,6 +15,8 @@ framework = arduino
|
|||||||
build_flags = -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
build_flags = -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
||||||
board_build.partitions = defaultWithSmallerSpiffs.csv
|
board_build.partitions = defaultWithSmallerSpiffs.csv
|
||||||
|
|
||||||
|
upload_port=/dev/ttyUSB0
|
||||||
|
|
||||||
; the latest development brankitchen-lightch (convention V3.0.x)
|
; the latest development brankitchen-lightch (convention V3.0.x)
|
||||||
lib_deps = ArduinoJson@6.16.1
|
lib_deps = ArduinoJson@6.16.1
|
||||||
https://github.com/homieiot/homie-esp8266.git#v3.0
|
https://github.com/homieiot/homie-esp8266.git#v3.0
|
||||||
|
@ -21,36 +21,35 @@
|
|||||||
//Printf debugging
|
//Printf debugging
|
||||||
//#define DS_DEBUG
|
//#define DS_DEBUG
|
||||||
|
|
||||||
int Ds18B20::readDevices() {
|
int Ds18B20::readDevices()
|
||||||
|
{
|
||||||
byte addr[8];
|
byte addr[8];
|
||||||
|
|
||||||
int amount = -1;
|
int amount = -1;
|
||||||
while (this->mDs->search(addr)) {
|
while (this->mDs->search(addr))
|
||||||
|
{
|
||||||
amount++;
|
amount++;
|
||||||
}
|
}
|
||||||
this->mDs->reset_search();
|
this->mDs->reset_search();
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Ds18B20::readAllTemperatures(float* pTemperatures, int maxTemperatures) {
|
int Ds18B20::readAllTemperatures(float *pTemperatures, int maxTemperatures)
|
||||||
|
{
|
||||||
byte addr[8];
|
byte addr[8];
|
||||||
uint8_t scratchPad[SCRATCHPADSIZE];
|
uint8_t scratchPad[SCRATCHPADSIZE];
|
||||||
int currentTemp = 0;
|
int currentTemp = 0;
|
||||||
#ifdef DS_DEBUG
|
|
||||||
int i;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (this->mDs->search(addr)) {
|
while (this->mDs->search(addr))
|
||||||
#ifdef DS_DEBUG
|
{
|
||||||
Serial.print(" ROM =");
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
Serial.write(' ');
|
|
||||||
Serial.print(addr[i], HEX);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
this->mDs->reset();
|
this->mDs->reset();
|
||||||
this->mDs->select(addr);
|
this->mDs->select(addr);
|
||||||
this->mDs->write(STARTCONV);
|
this->mDs->write(STARTCONV);
|
||||||
|
}
|
||||||
|
delay(750);
|
||||||
|
|
||||||
|
while (this->mDs->search(addr))
|
||||||
|
{
|
||||||
this->mDs->reset();
|
this->mDs->reset();
|
||||||
this->mDs->select(addr);
|
this->mDs->select(addr);
|
||||||
this->mDs->write(READSCRATCH);
|
this->mDs->write(READSCRATCH);
|
||||||
@ -68,31 +67,27 @@ int Ds18B20::readAllTemperatures(float* pTemperatures, int maxTemperatures) {
|
|||||||
// byte 7: DS18S20: COUNT_PER_C
|
// byte 7: DS18S20: COUNT_PER_C
|
||||||
// DS18B20 & DS1822: store for crc
|
// DS18B20 & DS1822: store for crc
|
||||||
// byte 8: SCRATCHPAD_CRC
|
// byte 8: SCRATCHPAD_CRC
|
||||||
#ifdef DS_DEBUG
|
for (uint8_t i = 0; i < 9; i++)
|
||||||
Serial.write("\r\nDATA:");
|
{
|
||||||
for (uint8_t i = 0; i < 9; i++) {
|
|
||||||
Serial.print(scratchPad[i], HEX);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
delay(50);
|
|
||||||
#endif
|
|
||||||
for (uint8_t i = 0; i < 9; i++) {
|
|
||||||
scratchPad[i] = this->mDs->read();
|
scratchPad[i] = this->mDs->read();
|
||||||
}
|
}
|
||||||
uint8_t crc8 = this->mDs->crc8(scratchPad, 8);
|
uint8_t crc8 = this->mDs->crc8(scratchPad, 8);
|
||||||
|
|
||||||
/* Only work an valid data */
|
/* Only work an valid data */
|
||||||
if (crc8 == scratchPad[OFFSET_CRC8]) {
|
if (crc8 == scratchPad[OFFSET_CRC8])
|
||||||
int16_t fpTemperature = (((int16_t) scratchPad[TEMP_MSB]) << 11)
|
{
|
||||||
| (((int16_t) scratchPad[TEMP_LSB]) << 3);
|
int16_t fpTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 11) | (((int16_t)scratchPad[TEMP_LSB]) << 3);
|
||||||
float celsius = (float)fpTemperature * 0.0078125;
|
float celsius = (float)fpTemperature * 0.0078125;
|
||||||
#ifdef DS_DEBUG
|
#ifdef DS_DEBUG
|
||||||
Serial.printf("\r\nTemp%d %f °C (Raw: %d, %x =? %x)\r\n", (currentTemp + 1), celsius, fpTemperature, crc8, scratchPad[8]);
|
Serial.printf("\r\nTemp%d %f °C (Raw: %d, %x =? %x)\r\n", (currentTemp + 1), celsius, fpTemperature, crc8, scratchPad[8]);
|
||||||
#endif
|
#endif
|
||||||
/* check, if the buffer as some space for our data */
|
/* check, if the buffer as some space for our data */
|
||||||
if (currentTemp < maxTemperatures) {
|
if (currentTemp < maxTemperatures)
|
||||||
|
{
|
||||||
pTemperatures[currentTemp] = celsius;
|
pTemperatures[currentTemp] = celsius;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,15 +11,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PlantCtrl.h"
|
#include "PlantCtrl.h"
|
||||||
|
#include "ControllerConfiguration.h"
|
||||||
|
|
||||||
Plant::Plant(int pinSensor, int pinPump,int plantId, HomieNode* plant, PlantSettings_t* setting) {
|
Plant::Plant(int pinSensor, int pinPump, int plantId, HomieNode *plant, PlantSettings_t *setting)
|
||||||
|
{
|
||||||
this->mPinSensor = pinSensor;
|
this->mPinSensor = pinSensor;
|
||||||
this->mPinPump = pinPump;
|
this->mPinPump = pinPump;
|
||||||
this->mPlant = plant;
|
this->mPlant = plant;
|
||||||
this->mSetting = setting;
|
this->mSetting = setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plant::init(void) {
|
void Plant::init(void)
|
||||||
|
{
|
||||||
/* Initialize Home Settings validator */
|
/* Initialize Home Settings validator */
|
||||||
this->mSetting->pSensorDry->setDefaultValue(DEACTIVATED_PLANT);
|
this->mSetting->pSensorDry->setDefaultValue(DEACTIVATED_PLANT);
|
||||||
this->mSetting->pSensorDry->setValidator([](long candidate) {
|
this->mSetting->pSensorDry->setValidator([](long candidate) {
|
||||||
@ -45,43 +48,50 @@ void Plant::init(void) {
|
|||||||
digitalWrite(this->mPinPump, LOW);
|
digitalWrite(this->mPinPump, LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plant::addSenseValue(void) {
|
void Plant::addSenseValue(void)
|
||||||
this->moistureRaw.add( analogRead(this->mPinSensor) );
|
{
|
||||||
|
int raw = analogRead(this->mPinSensor);
|
||||||
|
if(raw < MOIST_SENSOR_MAX_ADC && raw > MOIST_SENSOR_MIN_ADC){
|
||||||
|
this->moistureRaw.add(raw);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plant::postMQTTconnection(void) {
|
void Plant::postMQTTconnection(void)
|
||||||
|
{
|
||||||
const String OFF = String("OFF");
|
const String OFF = String("OFF");
|
||||||
this->mConnected = true;
|
this->mConnected = true;
|
||||||
this->mPlant->setProperty("switch").send(OFF);
|
this->mPlant->setProperty("switch").send(OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plant::deactivatePump(void) {
|
void Plant::deactivatePump(void)
|
||||||
|
{
|
||||||
digitalWrite(this->mPinPump, LOW);
|
digitalWrite(this->mPinPump, LOW);
|
||||||
if (this->mConnected) {
|
if (this->mConnected)
|
||||||
|
{
|
||||||
const String OFF = String("OFF");
|
const String OFF = String("OFF");
|
||||||
this->mPlant->setProperty("switch").send(OFF);
|
this->mPlant->setProperty("switch").send(OFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plant::activatePump(void) {
|
void Plant::activatePump(void)
|
||||||
|
{
|
||||||
digitalWrite(this->mPinPump, HIGH);
|
digitalWrite(this->mPinPump, HIGH);
|
||||||
if (this->mConnected) {
|
if (this->mConnected)
|
||||||
|
{
|
||||||
const String OFF = String("ON");
|
const String OFF = String("ON");
|
||||||
this->mPlant->setProperty("switch").send(OFF);
|
this->mPlant->setProperty("switch").send(OFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plant::advertise(void) {
|
void Plant::advertise(void)
|
||||||
|
{
|
||||||
// Advertise topics
|
// Advertise topics
|
||||||
this->mPlant->advertise("switch").setName("Pump 1")
|
this->mPlant->advertise("switch").setName("Pump 1").setDatatype("boolean");
|
||||||
.setDatatype("boolean");
|
|
||||||
//FIXME add .settable(this->switchHandler)
|
//FIXME add .settable(this->switchHandler)
|
||||||
this->mPlant->advertise("moist").setName("Percent")
|
this->mPlant->advertise("moist").setName("Percent").setDatatype("number").setUnit("%");
|
||||||
.setDatatype("number")
|
this->mPlant->advertise("moistraw").setName("adc").setDatatype("number").setUnit("3.3/4096V");
|
||||||
.setUnit("%");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* FIXME
|
/* FIXME
|
||||||
bool Plant::switchHandler(const HomieRange& range, const String& value) {
|
bool Plant::switchHandler(const HomieRange& range, const String& value) {
|
||||||
if (range.isRange) return false; // only one switch is present
|
if (range.isRange) return false; // only one switch is present
|
||||||
|
@ -63,16 +63,20 @@ void RunningMedian::clear()
|
|||||||
void RunningMedian::add(float value)
|
void RunningMedian::add(float value)
|
||||||
{
|
{
|
||||||
_ar[_idx++] = value;
|
_ar[_idx++] = value;
|
||||||
if (_idx >= _size) _idx = 0; // wrap around
|
if (_idx >= _size)
|
||||||
if (_cnt < _size) _cnt++;
|
_idx = 0; // wrap around
|
||||||
|
if (_cnt < _size)
|
||||||
|
_cnt++;
|
||||||
_sorted = false;
|
_sorted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float RunningMedian::getMedian()
|
float RunningMedian::getMedian()
|
||||||
{
|
{
|
||||||
if (_cnt == 0) return NAN;
|
if (_cnt == 0)
|
||||||
|
return NAN;
|
||||||
|
|
||||||
if (_sorted == false) sort();
|
if (_sorted == false)
|
||||||
|
sort();
|
||||||
|
|
||||||
if (_cnt & 0x01) // is it odd sized?
|
if (_cnt & 0x01) // is it odd sized?
|
||||||
{
|
{
|
||||||
@ -83,7 +87,8 @@ float RunningMedian::getMedian()
|
|||||||
|
|
||||||
float RunningMedian::getAverage()
|
float RunningMedian::getAverage()
|
||||||
{
|
{
|
||||||
if (_cnt == 0) return NAN;
|
if (_cnt == 0)
|
||||||
|
return NAN;
|
||||||
|
|
||||||
float sum = 0;
|
float sum = 0;
|
||||||
for (uint8_t i = 0; i < _cnt; i++)
|
for (uint8_t i = 0; i < _cnt; i++)
|
||||||
@ -95,13 +100,16 @@ float RunningMedian::getAverage()
|
|||||||
|
|
||||||
float RunningMedian::getAverage(uint8_t nMedians)
|
float RunningMedian::getAverage(uint8_t nMedians)
|
||||||
{
|
{
|
||||||
if ((_cnt == 0) || (nMedians == 0)) return NAN;
|
if ((_cnt == 0) || (nMedians == 0))
|
||||||
|
return NAN;
|
||||||
|
|
||||||
if (_cnt < nMedians) nMedians = _cnt; // when filling the array for first time
|
if (_cnt < nMedians)
|
||||||
|
nMedians = _cnt; // when filling the array for first time
|
||||||
uint8_t start = ((_cnt - nMedians) / 2);
|
uint8_t start = ((_cnt - nMedians) / 2);
|
||||||
uint8_t stop = start + nMedians;
|
uint8_t stop = start + nMedians;
|
||||||
|
|
||||||
if (_sorted == false) sort();
|
if (_sorted == false)
|
||||||
|
sort();
|
||||||
|
|
||||||
float sum = 0;
|
float sum = 0;
|
||||||
for (uint8_t i = start; i < stop; i++)
|
for (uint8_t i = start; i < stop; i++)
|
||||||
@ -113,7 +121,8 @@ float RunningMedian::getAverage(uint8_t nMedians)
|
|||||||
|
|
||||||
float RunningMedian::getElement(const uint8_t n)
|
float RunningMedian::getElement(const uint8_t n)
|
||||||
{
|
{
|
||||||
if ((_cnt == 0) || (n >= _cnt)) return NAN;
|
if ((_cnt == 0) || (n >= _cnt))
|
||||||
|
return NAN;
|
||||||
|
|
||||||
uint8_t pos = _idx + n;
|
uint8_t pos = _idx + n;
|
||||||
if (pos >= _cnt) // faster than %
|
if (pos >= _cnt) // faster than %
|
||||||
@ -125,16 +134,19 @@ float RunningMedian::getElement(const uint8_t n)
|
|||||||
|
|
||||||
float RunningMedian::getSortedElement(const uint8_t n)
|
float RunningMedian::getSortedElement(const uint8_t n)
|
||||||
{
|
{
|
||||||
if ((_cnt == 0) || (n >= _cnt)) return NAN;
|
if ((_cnt == 0) || (n >= _cnt))
|
||||||
|
return NAN;
|
||||||
|
|
||||||
if (_sorted == false) sort();
|
if (_sorted == false)
|
||||||
|
sort();
|
||||||
return _ar[_p[n]];
|
return _ar[_p[n]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// n can be max <= half the (filled) size
|
// n can be max <= half the (filled) size
|
||||||
float RunningMedian::predict(const uint8_t n)
|
float RunningMedian::predict(const uint8_t n)
|
||||||
{
|
{
|
||||||
if ((_cnt == 0) || (n >= _cnt / 2)) return NAN;
|
if ((_cnt == 0) || (n >= _cnt / 2))
|
||||||
|
return NAN;
|
||||||
|
|
||||||
float med = getMedian(); // takes care of sorting !
|
float med = getMedian(); // takes care of sorting !
|
||||||
if (_cnt & 0x01)
|
if (_cnt & 0x01)
|
||||||
@ -162,7 +174,8 @@ void RunningMedian::sort()
|
|||||||
flag = false;
|
flag = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (flag) break;
|
if (flag)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
_sorted = true;
|
_sorted = true;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
/**
|
/** \addtogroup Controller
|
||||||
|
* @{
|
||||||
|
*
|
||||||
* @file main.cpp
|
* @file main.cpp
|
||||||
* @author Ollo
|
* @author Ollo
|
||||||
* @brief PlantControl
|
* @brief PlantControl
|
||||||
@ -6,7 +8,6 @@
|
|||||||
* @date 2020-05-01
|
* @date 2020-05-01
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2020
|
* @copyright Copyright (c) 2020
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
#include "PlantCtrl.h"
|
#include "PlantCtrl.h"
|
||||||
#include "ControllerConfiguration.h"
|
#include "ControllerConfiguration.h"
|
||||||
@ -16,8 +17,8 @@
|
|||||||
#include "time.h"
|
#include "time.h"
|
||||||
#include "esp_sleep.h"
|
#include "esp_sleep.h"
|
||||||
#include "RunningMedian.h"
|
#include "RunningMedian.h"
|
||||||
#include <arduino-timer.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
const unsigned long TEMPREADCYCLE = 30000; /**< Check temperature all half minutes */
|
const unsigned long TEMPREADCYCLE = 30000; /**< Check temperature all half minutes */
|
||||||
|
|
||||||
@ -26,44 +27,36 @@ const unsigned long TEMPREADCYCLE = 30000; /**< Check temperature all half minut
|
|||||||
#define SOLAR4SENSORS 6.0f
|
#define SOLAR4SENSORS 6.0f
|
||||||
#define TEMP_INIT_VALUE -999.0f
|
#define TEMP_INIT_VALUE -999.0f
|
||||||
#define TEMP_MAX_VALUE 85.0f
|
#define TEMP_MAX_VALUE 85.0f
|
||||||
|
#define HalfHour 60
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
long lastActive; /**< Timestamp, a pump was activated */
|
||||||
|
long moistTrigger; /**< Trigger value of the moist sensor */
|
||||||
|
long moisture; /**< last measured moist value */
|
||||||
|
|
||||||
|
} rtc_plant_t;
|
||||||
|
|
||||||
/********************* non volatile enable after deepsleep *******************************/
|
/********************* non volatile enable after deepsleep *******************************/
|
||||||
|
RTC_DATA_ATTR rtc_plant_t rtcPlant[MAX_PLANTS];
|
||||||
RTC_DATA_ATTR long gotoMode2AfterThisTimestamp = 0;
|
RTC_DATA_ATTR long gotoMode2AfterThisTimestamp = 0;
|
||||||
RTC_DATA_ATTR long rtcDeepSleepTime = 0; /**< Time, when the microcontroller shall be up again */
|
RTC_DATA_ATTR long rtcDeepSleepTime = 0; /**< Time, when the microcontroller shall be up again */
|
||||||
RTC_DATA_ATTR long rtcLastActive0 = 0;
|
|
||||||
RTC_DATA_ATTR long rtcMoistureTrigger0 = 0; /**<Level for the moisture sensor */
|
|
||||||
RTC_DATA_ATTR long rtcLastActive1 = 0;
|
|
||||||
RTC_DATA_ATTR long rtcMoistureTrigger1 = 0; /**<Level for the moisture sensor */
|
|
||||||
RTC_DATA_ATTR long rtcLastActive2 = 0;
|
|
||||||
RTC_DATA_ATTR long rtcMoistureTrigger2 = 0; /**<Level for the moisture sensor */
|
|
||||||
RTC_DATA_ATTR long rtcLastActive3 = 0;
|
|
||||||
RTC_DATA_ATTR long rtcMoistureTrigger3 = 0; /**<Level for the moisture sensor */
|
|
||||||
RTC_DATA_ATTR long rtcLastActive4 = 0;
|
|
||||||
RTC_DATA_ATTR long rtcMoistureTrigger4 = 0; /**<Level for the moisture sensor */
|
|
||||||
RTC_DATA_ATTR long rtcLastActive5 = 0;
|
|
||||||
RTC_DATA_ATTR long rtcMoistureTrigger5 = 0; /**<Level for the moisture sensor */
|
|
||||||
RTC_DATA_ATTR long rtcLastActive6 = 0;
|
|
||||||
RTC_DATA_ATTR long rtcMoistureTrigger6 = 0; /**<Level for the moisture sensor */
|
|
||||||
RTC_DATA_ATTR int lastPumpRunning = 0;
|
RTC_DATA_ATTR int lastPumpRunning = 0;
|
||||||
RTC_DATA_ATTR long lastWaterValue = 0;
|
RTC_DATA_ATTR long lastWaterValue = 0;
|
||||||
|
RTC_DATA_ATTR float rtcLastTemp1 = 0.0f;
|
||||||
const char *ntpServer = "pool.ntp.org";
|
RTC_DATA_ATTR float rtcLastTemp2 = 0.0f;
|
||||||
|
RTC_DATA_ATTR int gBootCount = 0;
|
||||||
|
RTC_DATA_ATTR int gCurrentPlant = 0; /**< Value Range: 1 ... 7 (0: no plant needs water) */
|
||||||
|
|
||||||
bool warmBoot = true;
|
bool warmBoot = true;
|
||||||
bool mode3Active = false; /**< Controller must not sleep */
|
bool volatile mode3Active = false; /**< Controller must not sleep */
|
||||||
bool mDeepsleep = false;
|
bool volatile mDeepsleep = false;
|
||||||
|
|
||||||
int plantSensor1 = 0;
|
int plantSensor1 = 0;
|
||||||
|
|
||||||
int readCounter = 0;
|
int readCounter = 0;
|
||||||
bool mConfigured = false;
|
bool mConfigured = false;
|
||||||
|
|
||||||
auto wait4sleep = timer_create_default(); // create a timer with default settings
|
|
||||||
|
|
||||||
RTC_DATA_ATTR int gBootCount = 0;
|
|
||||||
RTC_DATA_ATTR int gCurrentPlant = 0; /**< Value Range: 1 ... 7 (0: no plant needs water) */
|
|
||||||
|
|
||||||
RunningMedian lipoRawSensor = RunningMedian(5);
|
RunningMedian lipoRawSensor = RunningMedian(5);
|
||||||
RunningMedian solarRawSensor = RunningMedian(5);
|
RunningMedian solarRawSensor = RunningMedian(5);
|
||||||
RunningMedian waterRawSensor = RunningMedian(5);
|
RunningMedian waterRawSensor = RunningMedian(5);
|
||||||
@ -91,11 +84,42 @@ float getSolarVoltage()
|
|||||||
return SOLAR_VOLT(solarRawSensor.getAverage());
|
return SOLAR_VOLT(solarRawSensor.getAverage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setMoistureTrigger(int plantId, long value)
|
||||||
|
{
|
||||||
|
if ((plantId >= 0) && (plantId < MAX_PLANTS))
|
||||||
|
{
|
||||||
|
rtcPlant[plantId].moistTrigger = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastMoisture(int plantId, long value)
|
||||||
|
{
|
||||||
|
if ((plantId >= 0) && (plantId < MAX_PLANTS))
|
||||||
|
{
|
||||||
|
rtcPlant[plantId].moisture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long getLastMoisture(int plantId)
|
||||||
|
{
|
||||||
|
if ((plantId >= 0) && (plantId < MAX_PLANTS))
|
||||||
|
{
|
||||||
|
return rtcPlant[plantId].moisture;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void readSystemSensors()
|
void readSystemSensors()
|
||||||
{
|
{
|
||||||
|
for (int i=0; i < 5; i++) {
|
||||||
lipoRawSensor.add(analogRead(SENSOR_LIPO));
|
lipoRawSensor.add(analogRead(SENSOR_LIPO));
|
||||||
solarRawSensor.add(analogRead(SENSOR_SOLAR));
|
solarRawSensor.add(analogRead(SENSOR_SOLAR));
|
||||||
}
|
}
|
||||||
|
Serial << "Lipo " << lipoRawSensor.getAverage() << " -> " << getBatteryVoltage() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
int determineNextPump();
|
int determineNextPump();
|
||||||
void setLastActivationForPump(int pumpId, long time);
|
void setLastActivationForPump(int pumpId, long time);
|
||||||
@ -107,39 +131,42 @@ long getCurrentTime()
|
|||||||
return tv_now.tv_sec;
|
return tv_now.tv_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
//wait till homie flushed mqtt ect.
|
|
||||||
bool prepareSleep(void *)
|
|
||||||
{
|
|
||||||
//FIXME wait till pending mqtt is done, then start sleep via event or whatever
|
|
||||||
//Homie.disableResetTrigger();
|
|
||||||
|
|
||||||
bool queueIsEmpty = true;
|
|
||||||
if (queueIsEmpty)
|
|
||||||
{
|
|
||||||
mDeepsleep = true;
|
|
||||||
}
|
|
||||||
return false; // repeat? true there is something in the queue to be done
|
|
||||||
}
|
|
||||||
|
|
||||||
void espDeepSleepFor(long seconds, bool activatePump = false)
|
void espDeepSleepFor(long seconds, bool activatePump = false)
|
||||||
{
|
{
|
||||||
delay(1500);
|
if (mode3Active)
|
||||||
|
{
|
||||||
|
Serial << "abort deepsleep, mode3Active" << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
long cTime = getCurrentTime();
|
||||||
|
if (cTime < 100000)
|
||||||
|
{
|
||||||
|
Serial << "Wait for ntp" << endl;
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
|
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
|
||||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF);
|
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF);
|
||||||
esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON);
|
esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON);
|
||||||
|
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
|
||||||
if (activatePump)
|
if (activatePump)
|
||||||
{
|
{
|
||||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
|
|
||||||
gpio_deep_sleep_hold_en();
|
gpio_deep_sleep_hold_en();
|
||||||
gpio_hold_en(GPIO_NUM_13); //pump pwr
|
gpio_hold_en(GPIO_NUM_13); //pump pwr
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_OFF);
|
|
||||||
gpio_hold_dis(GPIO_NUM_13); //pump pwr
|
gpio_hold_dis(GPIO_NUM_13); //pump pwr
|
||||||
gpio_deep_sleep_hold_dis();
|
gpio_deep_sleep_hold_dis();
|
||||||
digitalWrite(OUTPUT_PUMP, LOW);
|
digitalWrite(OUTPUT_PUMP, LOW);
|
||||||
|
digitalWrite(OUTPUT_SENSOR, LOW);
|
||||||
for (int i = 0; i < MAX_PLANTS; i++)
|
for (int i = 0; i < MAX_PLANTS; i++)
|
||||||
{
|
{
|
||||||
mPlants[i].deactivatePump();
|
mPlants[i].deactivatePump();
|
||||||
@ -148,19 +175,17 @@ void espDeepSleepFor(long seconds, bool activatePump = false)
|
|||||||
//gpio_hold_en(GPIO_NUM_23); //p0
|
//gpio_hold_en(GPIO_NUM_23); //p0
|
||||||
//FIXME fix for outher outputs
|
//FIXME fix for outher outputs
|
||||||
|
|
||||||
Serial.print("Going to sleep for ");
|
Serial.print("Trying to sleep for ");
|
||||||
Serial.print(seconds);
|
Serial.print(seconds);
|
||||||
Serial.println(" seconds");
|
Serial.println(" seconds");
|
||||||
esp_sleep_enable_timer_wakeup((seconds * 1000U * 1000U));
|
esp_sleep_enable_timer_wakeup((seconds * 1000U * 1000U));
|
||||||
wait4sleep.in(500, prepareSleep);
|
mDeepsleep = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mode2MQTT()
|
void mode2MQTT()
|
||||||
{
|
{
|
||||||
readSystemSensors();
|
readSystemSensors();
|
||||||
|
|
||||||
configTime(0, 0, ntpServer);
|
|
||||||
|
|
||||||
digitalWrite(OUTPUT_PUMP, LOW);
|
digitalWrite(OUTPUT_PUMP, LOW);
|
||||||
for (int i = 0; i < MAX_PLANTS; i++)
|
for (int i = 0; i < MAX_PLANTS; i++)
|
||||||
{
|
{
|
||||||
@ -169,7 +194,7 @@ void mode2MQTT()
|
|||||||
|
|
||||||
if (deepSleepTime.get())
|
if (deepSleepTime.get())
|
||||||
{
|
{
|
||||||
Serial << "sleeping for " << deepSleepTime.get() << endl;
|
Serial << "deepsleep time is configured to " << deepSleepTime.get() << endl;
|
||||||
}
|
}
|
||||||
/* Publish default values */
|
/* Publish default values */
|
||||||
|
|
||||||
@ -180,7 +205,23 @@ void mode2MQTT()
|
|||||||
}
|
}
|
||||||
for (int i = 0; i < MAX_PLANTS; i++)
|
for (int i = 0; i < MAX_PLANTS; i++)
|
||||||
{
|
{
|
||||||
mPlants[i].setProperty("moist").send(String(100 * mPlants[i].getSensorValue() / 4095));
|
long raw = mPlants[i].getCurrentMoisture();
|
||||||
|
long pct = 100 - map(raw, MOIST_SENSOR_MIN_ADC, MOIST_SENSOR_MAX_ADC, 0, 100);
|
||||||
|
if (raw == MISSING_SENSOR)
|
||||||
|
{
|
||||||
|
pct = 0;
|
||||||
|
}
|
||||||
|
if (pct < 0)
|
||||||
|
{
|
||||||
|
pct = 0;
|
||||||
|
}
|
||||||
|
if (pct > 100)
|
||||||
|
{
|
||||||
|
pct = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPlants[i].setProperty("moist").send(String(pct));
|
||||||
|
mPlants[i].setProperty("moistraw").send(String(raw));
|
||||||
}
|
}
|
||||||
sensorWater.setProperty("remaining").send(String(waterLevelMax.get() - waterRawSensor.getAverage()));
|
sensorWater.setProperty("remaining").send(String(waterLevelMax.get() - waterRawSensor.getAverage()));
|
||||||
Serial << "W : " << waterRawSensor.getAverage() << " cm (" << String(waterLevelMax.get() - waterRawSensor.getAverage()) << "%)" << endl;
|
Serial << "W : " << waterRawSensor.getAverage() << " cm (" << String(waterLevelMax.get() - waterRawSensor.getAverage()) << "%)" << endl;
|
||||||
@ -191,34 +232,31 @@ void mode2MQTT()
|
|||||||
sensorSolar.setProperty("percent").send(String((100 * solarRawSensor.getAverage()) / 4095));
|
sensorSolar.setProperty("percent").send(String((100 * solarRawSensor.getAverage()) / 4095));
|
||||||
sensorSolar.setProperty("volt").send(String(getSolarVoltage()));
|
sensorSolar.setProperty("volt").send(String(getSolarVoltage()));
|
||||||
|
|
||||||
float temp[2] = {TEMP_INIT_VALUE, TEMP_INIT_VALUE};
|
float t1 = temp1.getMedian();
|
||||||
float *pFloat = temp;
|
if (t1 != NAN)
|
||||||
int devices = dallas.readAllTemperatures(pFloat, 2);
|
|
||||||
if (devices < 2)
|
|
||||||
{
|
{
|
||||||
if ((pFloat[0] > TEMP_INIT_VALUE) && (pFloat[0] < TEMP_MAX_VALUE))
|
sensorTemp.setProperty("control").send(String(t1));
|
||||||
{
|
|
||||||
sensorTemp.setProperty("control").send(String(pFloat[0]));
|
|
||||||
}
|
}
|
||||||
}
|
float t2 = temp2.getMedian();
|
||||||
else if (devices >= 2)
|
if (t2 != NAN)
|
||||||
{
|
{
|
||||||
if ((pFloat[0] > TEMP_INIT_VALUE) && (pFloat[0] < TEMP_MAX_VALUE))
|
sensorTemp.setProperty("temp").send(String(t2));
|
||||||
{
|
|
||||||
sensorTemp.setProperty("temp").send(String(pFloat[0]));
|
|
||||||
}
|
|
||||||
if ((pFloat[1] > TEMP_INIT_VALUE) && (pFloat[1] < TEMP_MAX_VALUE))
|
|
||||||
{
|
|
||||||
sensorTemp.setProperty("control").send(String(pFloat[1]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lipoTempWarning = abs(temp[0] - temp[1]) > 5;
|
//give mqtt time, use via publish callback instead?
|
||||||
|
delay(100);
|
||||||
|
|
||||||
|
bool lipoTempWarning = t1 != 85 && t2 != 85 && abs(t1 - t2) > 10;
|
||||||
if (lipoTempWarning)
|
if (lipoTempWarning)
|
||||||
{
|
{
|
||||||
Serial.println("Lipo temp incorrect, panic mode deepsleep");
|
Serial.println("Lipo temp incorrect, panic mode deepsleep TODO");
|
||||||
espDeepSleepFor(PANIK_MODE_DEEPSLEEP);
|
//espDeepSleepFor(PANIK_MODE_DEEPSLEEP);
|
||||||
return;
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_PLANTS; i++)
|
||||||
|
{
|
||||||
|
setMoistureTrigger(i, mPlants[i].mSetting->pSensorDry->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasWater = true; //FIXMEmWaterGone > waterLevelMin.get();
|
bool hasWater = true; //FIXMEmWaterGone > waterLevelMin.get();
|
||||||
@ -229,24 +267,33 @@ void mode2MQTT()
|
|||||||
Serial.println("Want to pump but no water");
|
Serial.println("Want to pump but no water");
|
||||||
}
|
}
|
||||||
if (lastPumpRunning != -1 && hasWater)
|
if (lastPumpRunning != -1 && hasWater)
|
||||||
|
{
|
||||||
|
if (mode3Active)
|
||||||
|
{
|
||||||
|
Serial.println("Mode 3 active, ignoring pump request");
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
digitalWrite(OUTPUT_PUMP, HIGH);
|
digitalWrite(OUTPUT_PUMP, HIGH);
|
||||||
setLastActivationForPump(lastPumpRunning, getCurrentTime());
|
setLastActivationForPump(lastPumpRunning, getCurrentTime());
|
||||||
mPlants[lastPumpRunning].activatePump();
|
mPlants[lastPumpRunning].activatePump();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (lastPumpRunning == -1 || !hasWater)
|
if (lastPumpRunning == -1 || !hasWater)
|
||||||
{
|
{
|
||||||
if (getSolarVoltage() < SOLAR_CHARGE_MIN_VOLTAGE)
|
if (getSolarVoltage() < SOLAR_CHARGE_MIN_VOLTAGE)
|
||||||
{
|
{
|
||||||
gotoMode2AfterThisTimestamp = getCurrentTime() + deepSleepNightTime.get();
|
gotoMode2AfterThisTimestamp = getCurrentTime() + maxTimeBetweenMQTTUpdates.get();
|
||||||
Serial.println("No pumps to activate and low light, deepSleepNight");
|
Serial.println("No pumps to activate and low light, deepSleepNight");
|
||||||
espDeepSleepFor(deepSleepNightTime.get());
|
espDeepSleepFor(deepSleepNightTime.get());
|
||||||
|
rtcDeepSleepTime = deepSleepNightTime.get();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gotoMode2AfterThisTimestamp = getCurrentTime() + deepSleepTime.get();
|
gotoMode2AfterThisTimestamp = getCurrentTime() + maxTimeBetweenMQTTUpdates.get();
|
||||||
Serial.println("No pumps to activate, deepSleep");
|
Serial.println("No pumps to activate, deepSleep");
|
||||||
espDeepSleepFor(deepSleepTime.get());
|
espDeepSleepFor(deepSleepTime.get());
|
||||||
|
rtcDeepSleepTime = deepSleepTime.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -257,109 +304,47 @@ void mode2MQTT()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMoistureTrigger(int plantId, long value)
|
long getMoistureTrigger(int plantId)
|
||||||
{
|
{
|
||||||
if (plantId == 0)
|
if ((plantId >= 0) && (plantId < MAX_PLANTS))
|
||||||
{
|
{
|
||||||
rtcMoistureTrigger0 = value;
|
return rtcPlant[plantId].moistTrigger;
|
||||||
}
|
}
|
||||||
if (plantId == 1)
|
else
|
||||||
{
|
{
|
||||||
rtcMoistureTrigger1 = value;
|
return -1;
|
||||||
}
|
|
||||||
if (plantId == 2)
|
|
||||||
{
|
|
||||||
rtcMoistureTrigger2 = value;
|
|
||||||
}
|
|
||||||
if (plantId == 3)
|
|
||||||
{
|
|
||||||
rtcMoistureTrigger3 = value;
|
|
||||||
}
|
|
||||||
if (plantId == 4)
|
|
||||||
{
|
|
||||||
rtcMoistureTrigger4 = value;
|
|
||||||
}
|
|
||||||
if (plantId == 5)
|
|
||||||
{
|
|
||||||
rtcMoistureTrigger5 = value;
|
|
||||||
}
|
|
||||||
if (plantId == 6)
|
|
||||||
{
|
|
||||||
rtcMoistureTrigger6 = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLastActivationForPump(int plantId, long value)
|
void setLastActivationForPump(int plantId, long value)
|
||||||
{
|
{
|
||||||
if (plantId == 0)
|
if ((plantId >= 0) && (plantId < MAX_PLANTS))
|
||||||
{
|
{
|
||||||
rtcLastActive0 = value;
|
rtcPlant[plantId].lastActive = value;
|
||||||
}
|
|
||||||
if (plantId == 1)
|
|
||||||
{
|
|
||||||
rtcLastActive1 = value;
|
|
||||||
}
|
|
||||||
if (plantId == 2)
|
|
||||||
{
|
|
||||||
rtcLastActive2 = value;
|
|
||||||
}
|
|
||||||
if (plantId == 3)
|
|
||||||
{
|
|
||||||
rtcLastActive3 = value;
|
|
||||||
}
|
|
||||||
if (plantId == 4)
|
|
||||||
{
|
|
||||||
rtcLastActive4 = value;
|
|
||||||
}
|
|
||||||
if (plantId == 5)
|
|
||||||
{
|
|
||||||
rtcLastActive5 = value;
|
|
||||||
}
|
|
||||||
if (plantId == 6)
|
|
||||||
{
|
|
||||||
rtcLastActive6 = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long getLastActivationForPump(int plantId)
|
long getLastActivationForPump(int plantId)
|
||||||
{
|
{
|
||||||
if (plantId == 0)
|
if ((plantId >= 0) && (plantId < MAX_PLANTS))
|
||||||
{
|
{
|
||||||
return rtcLastActive0;
|
return rtcPlant[plantId].lastActive;
|
||||||
}
|
}
|
||||||
if (plantId == 1)
|
else
|
||||||
{
|
{
|
||||||
return rtcLastActive1;
|
|
||||||
}
|
|
||||||
if (plantId == 2)
|
|
||||||
{
|
|
||||||
return rtcLastActive2;
|
|
||||||
}
|
|
||||||
if (plantId == 3)
|
|
||||||
{
|
|
||||||
return rtcLastActive3;
|
|
||||||
}
|
|
||||||
if (plantId == 4)
|
|
||||||
{
|
|
||||||
return rtcLastActive4;
|
|
||||||
}
|
|
||||||
if (plantId == 5)
|
|
||||||
{
|
|
||||||
return rtcLastActive5;
|
|
||||||
}
|
|
||||||
if (plantId == 6)
|
|
||||||
{
|
|
||||||
return rtcLastActive6;
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sensors, that are connected to GPIOs, mandatory for WIFI.
|
* @brief Sensors, that are connected to GPIOs, mandatory for WIFI.
|
||||||
* These sensors (ADC2) can only be read when no Wifi is used.
|
* These sensors (ADC2) can only be read when no Wifi is used.
|
||||||
*/
|
*/
|
||||||
void readSensors()
|
bool readSensors()
|
||||||
{
|
{
|
||||||
|
float temp[2] = {TEMP_MAX_VALUE, TEMP_MAX_VALUE};
|
||||||
|
float *pFloat = temp;
|
||||||
|
bool leaveMode1 = false;
|
||||||
Serial << "Read Sensors" << endl;
|
Serial << "Read Sensors" << endl;
|
||||||
|
|
||||||
readSystemSensors();
|
readSystemSensors();
|
||||||
@ -368,7 +353,7 @@ void readSensors()
|
|||||||
pinMode(OUTPUT_SENSOR, OUTPUT);
|
pinMode(OUTPUT_SENSOR, OUTPUT);
|
||||||
digitalWrite(OUTPUT_SENSOR, HIGH);
|
digitalWrite(OUTPUT_SENSOR, HIGH);
|
||||||
|
|
||||||
delay(100);
|
delay(20);
|
||||||
/* wait before reading something */
|
/* wait before reading something */
|
||||||
for (int readCnt = 0; readCnt < AMOUNT_SENOR_QUERYS; readCnt++)
|
for (int readCnt = 0; readCnt < AMOUNT_SENOR_QUERYS; readCnt++)
|
||||||
{
|
{
|
||||||
@ -376,6 +361,19 @@ void readSensors()
|
|||||||
{
|
{
|
||||||
mPlants[i].addSenseValue();
|
mPlants[i].addSenseValue();
|
||||||
}
|
}
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < MAX_PLANTS; i++)
|
||||||
|
{
|
||||||
|
long current = mPlants[i].getCurrentMoisture();
|
||||||
|
long delta = abs(getLastMoisture(i) - current);
|
||||||
|
bool tmp = (delta > MOIST_DELTA_TRIGGER_ADC);
|
||||||
|
setLastMoisture(i, current);
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
leaveMode1 = true;
|
||||||
|
Serial.printf("Mode2 start due to moist delta in plant %d with %ld \r\n", i, delta);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial << "DS18B20" << endl;
|
Serial << "DS18B20" << endl;
|
||||||
@ -384,23 +382,33 @@ void readSensors()
|
|||||||
delay(200);
|
delay(200);
|
||||||
|
|
||||||
/* Required to read the temperature once */
|
/* Required to read the temperature once */
|
||||||
float temp[2] = {0, 0};
|
for (int i = 0; i < 5; i++)
|
||||||
float *pFloat = temp;
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
{
|
||||||
if (dallas.readAllTemperatures(pFloat, 2) > 0)
|
int sensors = dallas.readAllTemperatures(pFloat, 2);
|
||||||
|
if (sensors > 0)
|
||||||
{
|
{
|
||||||
Serial << "t1: " << String(temp[0]) << endl;
|
Serial << "t1: " << String(temp[0]) << endl;
|
||||||
Serial << "t2: " << String(temp[1]) << endl;
|
|
||||||
// first read returns crap, ignore result and read again
|
|
||||||
if (i <= 2)
|
|
||||||
{
|
|
||||||
temp1.add(temp[0]);
|
temp1.add(temp[0]);
|
||||||
|
}
|
||||||
|
if (sensors > 1)
|
||||||
|
{
|
||||||
|
Serial << "t2: " << String(temp[1]) << endl;
|
||||||
temp2.add(temp[1]);
|
temp2.add(temp[1]);
|
||||||
}
|
}
|
||||||
|
delay(50);
|
||||||
}
|
}
|
||||||
delay(200);
|
|
||||||
|
if ((temp1.getAverage() - rtcLastTemp1 > TEMPERATURE_DELTA_TRIGGER_IN_C) ||
|
||||||
|
(rtcLastTemp1 - temp1.getAverage() > TEMPERATURE_DELTA_TRIGGER_IN_C)) {
|
||||||
|
leaveMode1 = true;
|
||||||
}
|
}
|
||||||
|
if ((temp2.getAverage() - rtcLastTemp2 > TEMPERATURE_DELTA_TRIGGER_IN_C) ||
|
||||||
|
(rtcLastTemp2 - temp2.getAverage() > TEMPERATURE_DELTA_TRIGGER_IN_C)) {
|
||||||
|
leaveMode1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtcLastTemp1 = temp1.getAverage();
|
||||||
|
rtcLastTemp2 = temp2.getAverage();
|
||||||
|
|
||||||
/* Use the Ultrasonic sensor to measure waterLevel */
|
/* Use the Ultrasonic sensor to measure waterLevel */
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
@ -417,6 +425,7 @@ void readSensors()
|
|||||||
}
|
}
|
||||||
/* deactivate the sensors */
|
/* deactivate the sensors */
|
||||||
digitalWrite(OUTPUT_SENSOR, LOW);
|
digitalWrite(OUTPUT_SENSOR, LOW);
|
||||||
|
return leaveMode1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Homie.getMqttClient().disconnect();
|
//Homie.getMqttClient().disconnect();
|
||||||
@ -429,9 +438,11 @@ void onHomieEvent(const HomieEvent &event)
|
|||||||
Homie.getLogger() << "My statistics" << endl;
|
Homie.getLogger() << "My statistics" << endl;
|
||||||
break;
|
break;
|
||||||
case HomieEventType::MQTT_READY:
|
case HomieEventType::MQTT_READY:
|
||||||
|
Serial.printf("NTP Setup with server %s\r\n", ntpServer.get());
|
||||||
|
configTime(0, 0, ntpServer.get());
|
||||||
//wait for rtc sync?
|
//wait for rtc sync?
|
||||||
rtcDeepSleepTime = deepSleepTime.get();
|
rtcDeepSleepTime = deepSleepTime.get();
|
||||||
Serial << "MQTT ready " << rtcDeepSleepTime << " ms ds" << endl;
|
Serial << "Setup plants" << endl;
|
||||||
for (int i = 0; i < MAX_PLANTS; i++)
|
for (int i = 0; i < MAX_PLANTS; i++)
|
||||||
{
|
{
|
||||||
mPlants[i].postMQTTconnection();
|
mPlants[i].postMQTTconnection();
|
||||||
@ -444,8 +455,9 @@ void onHomieEvent(const HomieEvent &event)
|
|||||||
esp_deep_sleep_start();
|
esp_deep_sleep_start();
|
||||||
break;
|
break;
|
||||||
case HomieEventType::OTA_STARTED:
|
case HomieEventType::OTA_STARTED:
|
||||||
|
Homie.getLogger() << "OTA started" << endl;
|
||||||
digitalWrite(OUTPUT_SENSOR, HIGH);
|
digitalWrite(OUTPUT_SENSOR, HIGH);
|
||||||
digitalWrite(OUTPUT_PUMP, LOW);
|
digitalWrite(OUTPUT_PUMP, HIGH);
|
||||||
gpio_hold_dis(GPIO_NUM_13); //pump pwr
|
gpio_hold_dis(GPIO_NUM_13); //pump pwr
|
||||||
gpio_deep_sleep_hold_dis();
|
gpio_deep_sleep_hold_dis();
|
||||||
for (int i = 0; i < MAX_PLANTS; i++)
|
for (int i = 0; i < MAX_PLANTS; i++)
|
||||||
@ -455,6 +467,7 @@ void onHomieEvent(const HomieEvent &event)
|
|||||||
mode3Active = true;
|
mode3Active = true;
|
||||||
break;
|
break;
|
||||||
case HomieEventType::OTA_SUCCESSFUL:
|
case HomieEventType::OTA_SUCCESSFUL:
|
||||||
|
Homie.getLogger() << "OTA successfull" << endl;
|
||||||
digitalWrite(OUTPUT_SENSOR, LOW);
|
digitalWrite(OUTPUT_SENSOR, LOW);
|
||||||
digitalWrite(OUTPUT_PUMP, LOW);
|
digitalWrite(OUTPUT_PUMP, LOW);
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
@ -470,32 +483,46 @@ int determineNextPump()
|
|||||||
bool isLowLight = (solarValue > SOLAR_CHARGE_MIN_VOLTAGE || solarValue < SOLAR_CHARGE_MAX_VOLTAGE);
|
bool isLowLight = (solarValue > SOLAR_CHARGE_MIN_VOLTAGE || solarValue < SOLAR_CHARGE_MAX_VOLTAGE);
|
||||||
|
|
||||||
//FIXME instead of for, use sorted by last activation index to ensure equal runtime?
|
//FIXME instead of for, use sorted by last activation index to ensure equal runtime?
|
||||||
|
|
||||||
|
int pumpToUse = -1;
|
||||||
for (int i = 0; i < MAX_PLANTS; i++)
|
for (int i = 0; i < MAX_PLANTS; i++)
|
||||||
{
|
{
|
||||||
|
Plant plant = mPlants[i];
|
||||||
long lastActivation = getLastActivationForPump(i);
|
long lastActivation = getLastActivationForPump(i);
|
||||||
long sinceLastActivation = getCurrentTime() - lastActivation;
|
long sinceLastActivation = getCurrentTime() - lastActivation;
|
||||||
//this pump is in cooldown skip it and disable low power mode trigger for it
|
//this pump is in cooldown skip it and disable low power mode trigger for it
|
||||||
if (mPlants[i].isInCooldown(sinceLastActivation))
|
if (plant.isInCooldown(sinceLastActivation))
|
||||||
{
|
{
|
||||||
Serial.printf("%d Skipping due to cooldown\r\n", i);
|
Serial.printf("%d Skipping due to cooldown %ld / %ld \r\n", i, sinceLastActivation, plant.getCooldownInSeconds());
|
||||||
setMoistureTrigger(i, DEACTIVATED_PLANT);
|
setMoistureTrigger(i, DEACTIVATED_PLANT);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//skip as it is not low light
|
//skip as it is not low light
|
||||||
if (!isLowLight && mPlants[i].isAllowedOnlyAtLowLight())
|
if (!isLowLight && plant.isAllowedOnlyAtLowLight())
|
||||||
{
|
{
|
||||||
Serial.println("Skipping due to light");
|
Serial.printf("%d No pump required: due to light\r\n", i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (plant.getCurrentMoisture() == MISSING_SENSOR && plant.isPumpTriggerActive())
|
||||||
if (mPlants->isPumpRequired())
|
{
|
||||||
|
Serial.printf("%d No pump possible: missing sensor \r\n", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (plant.isPumpRequired())
|
||||||
{
|
{
|
||||||
Serial.printf("%d Requested pumping\r\n", i);
|
Serial.printf("%d Requested pumping\r\n", i);
|
||||||
return i;
|
pumpToUse = i;
|
||||||
}
|
}
|
||||||
Serial.printf("%d No pump required\r\n", i);
|
else if (plant.isPumpTriggerActive())
|
||||||
|
{
|
||||||
|
Serial.printf("%d No pump required: moisture acceptable %f / %ld\r\n", i, plant.getCurrentMoisture(), plant.getSettingsMoisture());
|
||||||
}
|
}
|
||||||
return -1;
|
else
|
||||||
|
{
|
||||||
|
Serial.printf("%d No pump required: disabled pump trigger \r\n", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pumpToUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -510,7 +537,6 @@ bool aliveHandler(const HomieRange &range, const String &value)
|
|||||||
{
|
{
|
||||||
if (range.isRange)
|
if (range.isRange)
|
||||||
return false; // only one controller is present
|
return false; // only one controller is present
|
||||||
Serial << value << endl;
|
|
||||||
if (value.equals("ON") || value.equals("On") || value.equals("1"))
|
if (value.equals("ON") || value.equals("On") || value.equals("1"))
|
||||||
{
|
{
|
||||||
mode3Active = true;
|
mode3Active = true;
|
||||||
@ -536,9 +562,11 @@ void systemInit()
|
|||||||
// Set default values
|
// Set default values
|
||||||
|
|
||||||
//in seconds
|
//in seconds
|
||||||
deepSleepTime.setDefaultValue(10);
|
maxTimeBetweenMQTTUpdates.setDefaultValue(120);
|
||||||
deepSleepNightTime.setDefaultValue(30);
|
deepSleepTime.setDefaultValue(60);
|
||||||
|
deepSleepNightTime.setDefaultValue(600);
|
||||||
wateringDeepSleep.setDefaultValue(5);
|
wateringDeepSleep.setDefaultValue(5);
|
||||||
|
ntpServer.setDefaultValue("pool.ntp.org");
|
||||||
|
|
||||||
/* waterLevelMax 1000 */ /* 100cm in mm */
|
/* waterLevelMax 1000 */ /* 100cm in mm */
|
||||||
waterLevelMin.setDefaultValue(50); /* 5cm in mm */
|
waterLevelMin.setDefaultValue(50); /* 5cm in mm */
|
||||||
@ -547,6 +575,7 @@ void systemInit()
|
|||||||
|
|
||||||
Homie.setLoopFunction(homieLoop);
|
Homie.setLoopFunction(homieLoop);
|
||||||
Homie.onEvent(onHomieEvent);
|
Homie.onEvent(onHomieEvent);
|
||||||
|
//Homie.disableLogging();
|
||||||
Homie.setup();
|
Homie.setup();
|
||||||
|
|
||||||
mConfigured = Homie.isConfigured();
|
mConfigured = Homie.isConfigured();
|
||||||
@ -589,63 +618,46 @@ void systemInit()
|
|||||||
|
|
||||||
bool mode1()
|
bool mode1()
|
||||||
{
|
{
|
||||||
Serial.println("m1");
|
Serial.println("==== Mode 1 ====");
|
||||||
Serial << getCurrentTime() << " curtime" << endl;
|
Serial << getCurrentTime() << " curtime" << endl;
|
||||||
|
|
||||||
/* Disable all sleeping stuff before reading sensors */
|
bool deltaTrigger = readSensors();
|
||||||
gpio_deep_sleep_hold_dis();
|
|
||||||
|
|
||||||
readSensors();
|
|
||||||
//queue sensor values for
|
//queue sensor values for
|
||||||
|
|
||||||
if ((rtcDeepSleepTime == 0) ||
|
if (deltaTrigger)
|
||||||
(rtcMoistureTrigger0 == 0) ||
|
|
||||||
(rtcMoistureTrigger1 == 0) ||
|
|
||||||
(rtcMoistureTrigger2 == 0) ||
|
|
||||||
(rtcMoistureTrigger3 == 0) ||
|
|
||||||
(rtcMoistureTrigger4 == 0) ||
|
|
||||||
(rtcMoistureTrigger5 == 0) ||
|
|
||||||
(rtcMoistureTrigger6 == 0))
|
|
||||||
{
|
{
|
||||||
Serial.println("RTCm2");
|
Serial.println("1 delta triggered, going to mode2");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (rtcDeepSleepTime == 0)
|
||||||
|
{
|
||||||
|
Serial.println("1 missing rtc value, going to mode2");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < MAX_PLANTS; i++)
|
||||||
|
{
|
||||||
|
long trigger = getMoistureTrigger(i);
|
||||||
|
if (trigger == 0)
|
||||||
|
{
|
||||||
|
Serial << "Missing rtc trigger " << i << endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (trigger == DEACTIVATED_PLANT)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
long raw = mPlants[i].getCurrentMoisture();
|
||||||
|
if (raw == MISSING_SENSOR)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (raw > trigger)
|
||||||
|
{
|
||||||
|
Serial << "plant " << i << " dry " << raw << " / " << trigger << " starting mode 2" << endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((rtcMoistureTrigger0 != DEACTIVATED_PLANT) && (mPlants[0].getSensorValue() < rtcMoistureTrigger0))
|
|
||||||
{
|
|
||||||
Serial.println("mt0");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ((rtcMoistureTrigger1 != DEACTIVATED_PLANT) && (mPlants[1].getSensorValue() < rtcMoistureTrigger1))
|
|
||||||
{
|
|
||||||
Serial.println("mt1");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ((rtcMoistureTrigger2 != DEACTIVATED_PLANT) && (mPlants[2].getSensorValue() < rtcMoistureTrigger2))
|
|
||||||
{
|
|
||||||
Serial.println("mt2");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ((rtcMoistureTrigger3 != DEACTIVATED_PLANT) && (mPlants[3].getSensorValue() < rtcMoistureTrigger3))
|
|
||||||
{
|
|
||||||
Serial.println("mt3");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ((rtcMoistureTrigger4 != DEACTIVATED_PLANT) && (mPlants[4].getSensorValue() < rtcMoistureTrigger4))
|
|
||||||
{
|
|
||||||
Serial.println("mt4");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ((rtcMoistureTrigger5 != DEACTIVATED_PLANT) && (mPlants[5].getSensorValue() < rtcMoistureTrigger5))
|
|
||||||
{
|
|
||||||
Serial.println("mt5");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ((rtcMoistureTrigger6 != DEACTIVATED_PLANT) && (mPlants[6].getSensorValue() < rtcMoistureTrigger6))
|
|
||||||
{
|
|
||||||
Serial.println("mt6");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//check how long it was already in mode1 if to long goto mode2
|
//check how long it was already in mode1 if to long goto mode2
|
||||||
|
|
||||||
long cTime = getCurrentTime();
|
long cTime = getCurrentTime();
|
||||||
@ -660,18 +672,22 @@ bool mode1()
|
|||||||
Serial.println("Starting mode 2 after specified mode1 time");
|
Serial.println("Starting mode 2 after specified mode1 time");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial << "Mode2 Timer " << gotoMode2AfterThisTimestamp << " curtime " << cTime << endl;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mode2()
|
void mode2()
|
||||||
{
|
{
|
||||||
Serial.println("m2");
|
Serial.println("==== Mode 2 ====");
|
||||||
systemInit();
|
systemInit();
|
||||||
|
|
||||||
/* Jump into Mode 3, if not configured */
|
/* Jump into Mode 3, if not configured */
|
||||||
if (!mConfigured)
|
if (!mConfigured)
|
||||||
{
|
{
|
||||||
Serial.println("m3");
|
Serial.println("==== Mode 3 ====");
|
||||||
mode3Active = true;
|
mode3Active = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -732,8 +748,7 @@ void setup()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Serial.println("nop");
|
Serial.println("nop");
|
||||||
Serial.flush();
|
espDeepSleepFor(rtcDeepSleepTime);
|
||||||
esp_deep_sleep_start();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,22 +756,36 @@ void setup()
|
|||||||
* @brief Cyclic call
|
* @brief Cyclic call
|
||||||
* Executs the Homie base functionallity or triggers sleeping, if requested.
|
* Executs the Homie base functionallity or triggers sleeping, if requested.
|
||||||
*/
|
*/
|
||||||
|
long nextBlink = 0;
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
if (!mDeepsleep)
|
if (!mDeepsleep || mode3Active)
|
||||||
{
|
{
|
||||||
Homie.loop();
|
Homie.loop();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Serial << "Bye" << endl;
|
||||||
|
Serial.flush();
|
||||||
esp_deep_sleep_start();
|
esp_deep_sleep_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (millis() > 30000 && !mode3Active)
|
if (millis() > 30000 && !mode3Active)
|
||||||
{
|
{
|
||||||
Serial << (millis() / 1000) << "s alive" << endl;
|
Serial << (millis() / 1000) << "not terminated watchdog putting to sleep" << endl;
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
esp_deep_sleep_start();
|
espDeepSleepFor(rtcDeepSleepTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Toggel Senor LED to visualize mode 3 */
|
||||||
|
if (mode3Active)
|
||||||
|
{
|
||||||
|
if (nextBlink < millis())
|
||||||
|
{
|
||||||
|
nextBlink = millis() + 500;
|
||||||
|
digitalWrite(OUTPUT_SENSOR, !digitalRead(OUTPUT_SENSOR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @}*/
|
Loading…
Reference in New Issue
Block a user