-
Notifications
You must be signed in to change notification settings - Fork 2
/
microsdi12.py
175 lines (153 loc) · 6.62 KB
/
microsdi12.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
from machine import Pin
from machine import UART
import utime
import sys
class SDI12:
def __init__(self, pin_txd, pin_rxd, pin_direction=None, uart_bus_id=1):
self.pin_txd = pin_txd
self.pin_rxd = pin_rxd
self.pin_dir = pin_direction
self.uart = None
self.uart_bus_id = uart_bus_id
self.is_esp32 = (sys.platform.lower() == "esp32")
self.char_wait_duration_us = 8333
self.enable_wait_after_uart_write = True
self.dual_direction_pins = False
self.pin_drv = None
self.pin_rcv = None
self.delay_ms_after_send = None
def set_dual_direction_pins(self, pin_drv, pin_rcv):
self.pin_drv = pin_drv
self.pin_rcv = pin_rcv
self.dual_direction_pins = True
def wait_after_each_send(self, delay_ms):
self.delay_ms_after_send = delay_ms
def set_timing_params(self, char_wait_duration_us):
self.char_wait_duration_us = char_wait_duration_us
def set_wait_after_uart_write(self, wait_enabled):
self.enable_wait_after_uart_write = wait_enabled
def _send(self, cmd, timeout_ms=2500, termination_line=None):
if self.uart:
self.uart.deinit()
self.p_tx = Pin(self.pin_txd, mode=Pin.OUT)
self.p_dir = None
if self.pin_dir:
self.p_dir = Pin(self.pin_dir, mode=Pin.OUT)
elif self.dual_direction_pins:
self.p_drv = Pin(self.pin_drv, mode=Pin.OUT)
self.p_rcv = Pin(self.pin_rcv, mode=Pin.OUT)
self.p_tx.value(0)
if self.p_dir:
self.p_dir.value(1) # set output dir
elif self.dual_direction_pins:
self.p_drv.value(1)
self.p_rcv.value(1)
utime.sleep_us(int(self.char_wait_duration_us * 1.5)) # send BREAK
self.p_tx.value(1)
utime.sleep_us(self.char_wait_duration_us) # send MARK
if self.is_esp32:
self.uart = UART(self.uart_bus_id, baudrate=1200, bits=7, parity=2, stop=1, tx=self.pin_txd, rx=self.pin_rxd, timeout_char=75)
self.uart.init(baudrate=1200, bits=7, parity=2, stop=1, tx=self.pin_txd, rx=self.pin_rxd, timeout_char=75)
else:
self.uart = UART(self.uart_bus_id, baudrate=1200, bits=7, parity=UART.EVEN, stop=1, timeout_chars=75, pins=(self.pin_txd, self.pin_rxd))
print("SDI12 > [" + cmd + "]")
self.uart.write(cmd) # send command
if self.enable_wait_after_uart_write:
utime.sleep_us(8333 * len(cmd)) # wait to send command (byte time * command length)
if self.pin_dir:
self.p_dir.value(0) # output set to read
elif self.dual_direction_pins:
self.p_drv.value(0)
self.p_rcv.value(0)
start_timestamp = utime.ticks_ms()
timeout_timestamp = start_timestamp + timeout_ms
line = ""
while True:
remaining_bytes = self.uart.any()
if(utime.ticks_ms() >= timeout_timestamp):
break
if remaining_bytes > 0:
line_cur = self.uart.readline()
if line_cur:
try:
line_cur = line_cur.decode('utf-8').strip()
line += '\n' + line_cur
print(" < [" + line_cur + "]")
if termination_line is not None:
if line_cur == termination_line:
break
else:
break
except:
print("! " + str(line))
utime.sleep_ms(100)
if self.delay_ms_after_send:
utime.sleep_ms(self.delay_ms_after_send)
return line.strip() if line != "" else None
def is_active(self, address):
ack_act_cmd_resp = self._send(address + '!')
return (ack_act_cmd_resp == address)
def get_sensor_info(self, address):
manufacturer = None
model = None
id_cmd_resp = self._send(address + 'I!')
if id_cmd_resp:
responseParts = id_cmd_resp.split(' ')
manufacturer = responseParts[0][3:]
model = ' '.join(responseParts[1:]).strip()
return (manufacturer, model)
def get_measurement(self, address, measurement_name="M"):
values = None
# Request
nonconcur_meas_cmd_resp = self._send(address + measurement_name + '!')
if nonconcur_meas_cmd_resp and len(nonconcur_meas_cmd_resp) == 5:
seconds_to_wait_max = int(nonconcur_meas_cmd_resp[1:4])
number_of_measurements = int(nonconcur_meas_cmd_resp[4])
timeout = utime.ticks_ms() + seconds_to_wait_max * 1000
pending_bytes = self.uart.any()
while utime.ticks_ms() < timeout and pending_bytes == 0:
pending_bytes = self.uart.any()
if pending_bytes > 0:
try:
line = self.uart.readline()
print(" <~ [" + line.decode('utf-8').strip() + "]")
except:
print(" <~! [" + str(line) + "]")
break
utime.sleep_ms(10)
i = 0
values_read = 0
values = []
max_i = 9 # safety measure in case the sensor is unresponsive
while values_read < number_of_measurements and i < max_i:
resp = self._send(address + 'D' + str(i) + '!')
values = values + self._measurement_to_array(resp)
values_read = len(values)
i += 1
return values
def _measurement_to_array(self, measurement_response):
values = []
try:
# start from index 1 since response[0] is the address
i = 1
while i < len(measurement_response):
c = measurement_response[i]
if c == "-":
values.append(c)
elif c == "+":
values.append("")
else:
values[-1] += c
i += 1
except Exception as e:
print("Error processing generic sdi response: [{}]".format(measurement_response))
return values
def close(self):
if self.dual_direction_pins:
try:
self.p_drv.value(0)
self.p_rcv.value(1)
except:
pass
if self.uart:
self.uart.deinit()