1
1
import machine
2
2
import utime
3
-
4
- from utils import MQTTWriter , Slack , Ubidots , current_time , force_garbage_collect
3
+ from utils import (
4
+ MQTTWriter ,
5
+ Slack ,
6
+ Ubidots ,
7
+ adc_map ,
8
+ average ,
9
+ current_time ,
10
+ force_garbage_collect ,
11
+ )
12
+ from water_pump import WaterPump
5
13
6
14
7
15
class MoistureSensor (object ):
8
- def __init__ (self , adc_pin , config_dict ):
16
+ def __init__ (self , config_dict ):
9
17
"""
10
18
Sensor calibration
11
19
######################
@@ -16,35 +24,55 @@ def __init__(self, adc_pin, config_dict):
16
24
Expects a dict:
17
25
config_dict = {"moisture_sensor_cal": {"dry": 841, "wet": 470}
18
26
"""
19
- self .adc_pin = adc_pin
20
27
self .config = config_dict
21
- self .setup_adc
28
+ self ._adc = None
29
+ self ._mqtt = None
22
30
self ._slack = None
23
- self .ubidots = Ubidots (
24
- self .config ["ubidots" ]["token" ], self .config ["ubidots" ]["device" ]
25
- )
26
- # self._mqtt = None
31
+ self ._ubidots = None
32
+ self ._water_me = False
33
+ self ._water_pump = None
34
+
35
+ @property
36
+ def ubidots (self ):
37
+ if (self .config ["ubidots" ]["token" ]) and (not self ._ubidots ):
38
+ self ._ubidots = Ubidots (
39
+ self .config ["ubidots" ]["token" ], self .config ["ubidots" ]["device" ]
40
+ )
41
+ return self ._ubidots
42
+
43
+ @property
44
+ def water_pump (self ):
45
+ if (isinstance (self .config ["Pin_Config" ]["Water_Pump_Pin" ], int )) and (
46
+ not self ._water_pump
47
+ ):
48
+ self ._water_pump = WaterPump (
49
+ self .config ["Pin_Config" ]["Water_Pump_Pin" ],
50
+ self .config ["water_pump_time" ]["delay_pump_on" ],
51
+ )
52
+ return self ._water_pump
27
53
28
54
@property
29
- def setup_adc (self ):
30
- self .adc = machine .ADC (self .adc_pin )
55
+ def adc (self ):
56
+ if (isinstance (self .config ["Pin_Config" ]["ADC_Pin" ], int )) and (not self ._adc ):
57
+ self ._adc = machine .ADC (self .config ["Pin_Config" ]["ADC_Pin" ])
58
+ return self ._adc
31
59
32
60
@property
33
61
def slack (self ):
34
62
"""Slack message init"""
35
- config = self .config ["slack_auth" ]
36
- self ._slack = Slack (config ["app_id" ], config ["secret_id" ], config ["token" ])
63
+ if (self .config ["slack_auth" ].get ("app_id" )) and (not self ._slack ):
64
+ self ._slack = Slack (
65
+ self .config ["slack_auth" ]["app_id" ],
66
+ self .config ["slack_auth" ]["secret_id" ],
67
+ self .config ["slack_auth" ]["token" ],
68
+ )
37
69
return self ._slack .slack_it
38
70
39
- # @property
40
- # def mqtt(self):
41
- # host = self.config["MQTT_config"]["Host"]
42
- # self._mqtt = MQTTWriter(host)
43
- # return self._mqtt
44
-
45
- def average (self , samples ):
46
- ave = sum (samples , 0.0 ) / len (samples )
47
- return ave if ave > 0 else 0
71
+ @property
72
+ def mqtt (self ):
73
+ if (self .config ["MQTT_config" ].get ("Host" )) and (not self ._mqtt ):
74
+ self ._mqtt = MQTTWriter (self .config ["MQTT_config" ]["Host" ])
75
+ return self ._mqtt
48
76
49
77
def read_samples (self , n_samples = 10 , rate = 0.5 ):
50
78
sampled_adc = []
@@ -54,69 +82,62 @@ def read_samples(self, n_samples=10, rate=0.5):
54
82
force_garbage_collect ()
55
83
return sampled_adc
56
84
57
- def adc_map (self , current_val , fromLow , fromHigh , toLow , toHigh ):
58
- """
59
- Re-maps a number from one range to another.
60
- That is, a value of 'fromLow' would get mapped to 'toLow',
61
- a value of 'fromHigh' to 'toHigh', values in-between to values in-between, etc.
62
-
63
- Does not constrain values to within the range, because out-of-range values are
64
- sometimes intended and useful.
65
-
66
- y = adc_map(x, 1, 50, 50, 1);
67
-
68
- The function also handles negative numbers well, so that this example
69
-
70
- y = adc_map(x, 1, 50, 50, -100);
71
-
72
- is also valid and works well.
73
-
74
- The adc_map() function uses integer math so will not generate fractions,
75
- when the math might indicate that it should do so.
76
- Fractional remainders are truncated, and are not rounded or averaged.
77
-
78
- Parameters
79
- ----------
80
- value: the number to map.
81
- fromLow: the lower bound of the value’s current range.
82
- fromHigh: the upper bound of the value’s current range.
83
- toLow: the lower bound of the value’s target range.
84
- toHigh: the upper bound of the value’s target range.
85
-
86
- Adapted from https://www.arduino.cc/reference/en/language/functions/math/map/
87
- """
88
-
89
- return (current_val - fromLow ) * (toHigh - toLow ) / (fromHigh - fromLow ) + toLow
85
+ def message_send (self , msg ):
86
+ try :
87
+ print ("[INFO] Sending message to SLACK" )
88
+ self .slack (msg )
89
+ print ("[INFO] Message sent..." )
90
+ except Exception as exc :
91
+ print ("[ERROR] Could not send SLACK message: %s" % str (exc ))
92
+ finally :
93
+ print ("[INFO] %s" % msg )
90
94
91
95
def soil_sensor_check (self ):
92
96
try :
93
97
samples = self .read_samples ()
94
- sampled_adc = self . average (samples )
95
- SoilMoistPerc = self . adc_map (
98
+ sampled_adc = average (samples )
99
+ self . _soilmoistperc = adc_map (
96
100
sampled_adc ,
97
101
self .config ["moisture_sensor_cal" ]["dry" ],
98
102
self .config ["moisture_sensor_cal" ]["wet" ],
99
- 0 ,
100
- 100 ,
101
103
)
102
- self .ubidots .post_request ({"soil_moisture" : SoilMoistPerc })
103
- if SoilMoistPerc <= self .config ["moisture_sensor_cal" ].get ("Threshold" , 15 ):
104
- msg = "Soil Moisture Sensor: %.2f%% \t %s" % (
105
- SoilMoistPerc ,
106
- current_time (),
104
+ self .ubidots .post_request ({"soil_moisture" : self ._soilmoistperc })
105
+ if self ._soilmoistperc <= self .config ["moisture_sensor_cal" ].get (
106
+ "Threshold" , 50
107
+ ):
108
+ self ._water_me = True
109
+ self .message_send (
110
+ "[INFO] Soil Moisture Sensor: %.2f%% \t %s"
111
+ % (self ._soilmoistperc , current_time ())
107
112
)
108
- self .slack (msg )
109
- print (msg )
110
- elif SoilMoistPerc <= 70 :
111
- msg = "Soil Moisture is at 50% You should probably Water the plant."
112
- self .slack (msg )
113
- print (msg )
114
- force_garbage_collect ()
113
+ else :
114
+ self ._water_me = False
115
115
except Exception as exc :
116
116
print ("Exception: %s" , exc )
117
+ finally :
118
+ force_garbage_collect ()
117
119
118
120
def run_timer (self , secs = 60 ):
121
+ print ("[INFO] Timer Initialised, callback will be ran every %s seconds!!!" % secs )
119
122
while True :
120
123
self .soil_sensor_check ()
124
+ while self ._water_me :
125
+ self .message_send (
126
+ "Note: Automatically watering the plant(s):\t %s" % current_time ()
127
+ )
128
+ if not self .water_pump .pump_status :
129
+ self .water_pump .pump_on ()
130
+ print (
131
+ "[DEBUG] Setting Pump ON as water is @ %.2f%%"
132
+ % self ._soilmoistperc
133
+ )
134
+ if self .water_pump .pump_status :
135
+ print ("[DEBUG] Checking Soil Moisture Status..." )
136
+ self .soil_sensor_check ()
137
+ print ("[DEBUG] Soil Moisture Percent @ %.2f%%" % self ._soilmoistperc )
138
+ self .water_pump .pump_off ()
139
+ print (
140
+ "[DEBUG] Setting Pump OFF as water is @ %.2f%%" % self ._soilmoistperc
141
+ )
142
+
121
143
utime .sleep (secs )
122
- print ("Timer Initialised, callback will be ran every %s seconds!!!" % secs )
0 commit comments