Skip to content

Commit

Permalink
ESP32 support + bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
ftylitak committed Feb 8, 2022
1 parent 85de106 commit 1cf51e4
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 19 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,17 @@ Sends a request for data measurement to the sensor and returns the data provided
```
* args:
* SDI-12 sensor address. Typical range: 0-9.
* measurement_name: Configures the name of the query. Default is "M" as the default query is "aM!".
* measurement_name: Configures the name of the query. Default is "M" as the default query is "aM!".
* returns:
* Measurement data array: an array containing all the data collected from the sensor. For details on each data value, please advise sensor manufacturer manuals. If sensor is unreachable, returns `None`

**set_timing_params** (char_wait_duration_us):

Set the time needed for a character to be transmitted over UART. Used to calculate the sleep periods to ensure a character has been fully transmitted (ex. time to keep HIGH/LOW the direction and transmission pins for BREAK or MARK for SDI12). Default: 8333us

**set_wait_after_uart_write** (wait_enabled):

Enable/disable the sleep command after a UART write. For micropython implementations that uart.write calls uart_wait_tx_done, this sleep can be deactivated. If enabled, after UART write, the application sleeps for (char_wait_duration_us) * (number of command characters).

# Example

Expand Down
74 changes: 56 additions & 18 deletions microsdi12.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,69 @@
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.p_tx = Pin(pin_txd, mode=Pin.OUT)
self.p_dir = None
if pin_direction:
self.p_dir = Pin(pin_direction, mode=Pin.OUT)
self.uart = UART(uart_bus_id)
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

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):
self.uart.deinit()
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)

self.p_tx.value(0)
if self.p_dir:
self.p_dir.value(1) # set output dir
utime.sleep_us(12500) # send BREAK
utime.sleep_us(int(self.char_wait_duration_us * 1.5)) # send BREAK
self.p_tx.value(1)
utime.sleep_us(8333) # send MARK
self.uart.init(baudrate=1200, bits=7, parity=UART.EVEN, stop=1, timeout_chars=75, pins=(self.pin_txd, self.pin_rxd)) # init with given parameters
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)
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
utime.sleep_us(8333 * len(cmd)) # wait to send command (byte time * command length)
if self.p_dir:
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
line = self.uart.readline() # read data from UART
if line:
line = line.decode('utf-8').strip()
print(" < [" + line + "]")

start_timestamp = utime.ticks_ms()
timeout_timestamp = start_timestamp + 2500
line = None
while True:
remaining_bytes = self.uart.any()
if(utime.ticks_ms() >= timeout_timestamp):
break

line = self.uart.readline()
if line:
try:
line = line.decode('utf-8').strip()
print(" < [" + line + "]")
break
except:
print("! " + str(line))
utime.sleep_ms(100)
return line

def is_active(self, address):
Expand All @@ -52,22 +85,27 @@ def get_measurement(self, address, measurement_name="M"):
# 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:3])
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:
self.uart.readline()
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 = []
while values_read < number_of_measurements:
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)
Expand Down

0 comments on commit 1cf51e4

Please sign in to comment.