Skip to content

Commit 810eee4

Browse files
committed
add thoughts
1 parent dedd931 commit 810eee4

File tree

4 files changed

+76
-39
lines changed

4 files changed

+76
-39
lines changed

README.md

+42-10
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,57 @@
33
Components:
44

55
- SDS011 particulate sensor
6-
- Wemos D1 mini pro (ESP8266)
6+
- Wemos D1 mini pro (based on ESP8266)
77
- Some wires
88

99
Ultra simple wiring and ultra simple programming with Micropython! The SDS011 communicates over serial with a protocol detailed here http://cl.ly/ekot:
1010

11-
SDS011 Wemos
11+
SDS011 -- Wemos
1212

13-
TX --> RX
14-
RX <-- TX
15-
5v <-- 5v
16-
GND --> GND
13+
TX -- RX
14+
RX -- TX
15+
5v -- 5v
16+
GND -- GND
1717

1818
Wemos has only one serial-in and Micropython has no software serial library, so the device cannot be accessed when it is connected to the sensor. Luckily, the webrepl can be used to interact with the device instead.
1919

20-
Ideally, the sensor would be put to sleep and woken periodically. While the sleep command works, I CANNOT GET THE SENSOR TO WAKE UP!
20+
Ideally, the sensor would be put to sleep and woken periodically. There are some issues with this:
21+
- Printing anything to webrepl wakes the sensor up and it ceases to interpret sleep and wake signals properly
22+
- Sending the Wemos into deep sleep also wakes up the sensor!
2123

22-
Entering deep sleep on the Wemos does not help as the SDS011 continues to draw power.
24+
As a temporary workaround, I am using the dutycycle mode on the SDS011. This helps to preserve the life of the sensor and is fine for indoor use, but is not a good solution for battery operation because:
25+
- The sensor periodically wakes up, waits 60 secs, then issues a single reading before sleeping again. Since the documented initialization time of the sensor is 30 secs (and in my experience more like 10), that's a lot of wasted fan-time.
26+
- The Wemos remains fully powered, drawing 50-200mA (although light sleep might be possible for around 1mA)
2327

24-
As a temporary workaround, I am using the dutycycle mode: the Wemos remains on and the sensor kicks in every minute or so.
28+
## Going outdoors
2529

26-
TODO: investigate having the sensor wake up the Wemos from deep sleep when the dutycycle kicks in.
30+
Some possible solutions for an immobile battery-operated version:
31+
1) Use the dutycycle mode with a sleeping Wemos, but have the sensor initialization wake up the Wemos with a low pulse to RST (may not work if deep sleep interferes with the dutycycle). Requires a flip-flop circuit (https://github.com/esp8266/Arduino/issues/1488)?
32+
2) Use something (relay? MOSFET?) between the Wemos and the SDS011 to cut the connection before entering deep sleep.
33+
3) Hook the whole circuit to a MOSFET controlled by an ATiny85 or similar. This would provide better efficiency (because we would be sleeping the ATiny85 instead of the Wemos, which would be completely powered down), but is more complicated.
2734

35+
Let's evaluate some options assuming a 10 minute wake interval, 30 sec working period (so 3 minutes / hour awake), and the following power factors:
36+
- SDS011 consumes 70mA (awake) or <4mA (asleep)
37+
- Wemos consumes 150mA on average when awake or 5mA in light sleep
38+
- Deepsleep on Wemos consumes 2/3 times more than on esp8266 because of the USB-TTL converter: probably equates to around 0.1mA in total
39+
- At 1MHz the ATTiny85 consumes 2.5mA (awake) or 0.0005mA (asleep)
40+
- 3 AA batteries providing 7200mAh total
41+
- 70% efficiency
42+
43+
As is: (7200 * 60 * 0.7) / (3 * (70 + 150) + 57 * (150 + 4) = 32 hours
44+
45+
Without ATTiny but with relay: (7200 * 60 * 0.7) / (3 * (70 + 150) + 57 * 0.1) = 454 hours or 19 days
46+
47+
With ATTiny: (7200 * 60 * 0.7) / (3 * (70 + 150 + 2.5) + 57 * 0.0005) = 453 hours
48+
49+
What about using the ATTiny and turning on the Wemos only for last 7 secs of 30sec working period (say, 0.7 mins / hour @ 200mA)? (7200 * 60 * 0.7) / (3 * (70 + 2.5) + 0.7 * 200 + 57 * 0.0005) = 845 hours or 35 days.
50+
51+
If the Wemos can request time and pass it to ATTiny85, we can sleep 6 hours at night as well, bringing us up to around 1120 hours.
52+
53+
## Portability
54+
55+
Another desideratum is the ability pair with a phone and transmit on the fly, or store measurements for transmission later.
56+
57+
Storing: by default we get 6 bytes of data every second. After 30 mins that's 11kb. The Wemos has 96 kb of data RAM so we should be fine... We could also move into the 4 mb of flash, but must be careful as it is limited to 100,000 write/erase cycles.
58+
59+
For gps data we need the phone. It should be possible for the phone to connect to the Wemos set up as an access point. Battery life on wifi might be expected to be 7200 * 0.7 / 200 = 25 hours. But it might make more sense to move to the ESP32 (which also has bluetooth) for this.

boot.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import utime as time
77
gc.collect()
88

9-
print('\nbooting...')
9+
# print('\nbooting...')
1010

1111
def do_connect():
1212
import network
@@ -17,19 +17,19 @@ def do_connect():
1717

1818
ap_if = network.WLAN(network.AP_IF)
1919
ap_if.config(essid='Polly', password=pw)
20-
print('access point Polly open')
20+
# print('access point Polly open')
2121

2222
sta_if = network.WLAN(network.STA_IF)
2323
if not sta_if.isconnected():
24-
print('connecting to network...')
24+
# print('connecting to network...')
2525
sta_if.active(True)
2626
sta_if.connect('Bam-net', pw)
2727
while not sta_if.isconnected():
2828
pass
29-
print('connected at:', sta_if.ifconfig())
29+
# print('connected at:', sta_if.ifconfig())
3030

3131
do_connect()
3232
webrepl.start()
3333
time.sleep(1)
34-
print('Booted!')
34+
# print('Booted!')
3535

main.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
66
print('Woke from a deep sleep')
77

8-
READ_SECONDS = 55
9-
SLEEP_SECONDS = 5
8+
READ_SECONDS = 20
9+
SLEEP_SECONDS = 600
10+
DUTYCYCLE_REST_MINS = 2
1011

11-
sds011.set_dutycycle(1)
12-
sds011.read();
12+
# sds011.set_dutycycle(DUTYCYCLE_REST_MINS)
13+
print('Reading from sds011 for', READ_SECONDS, 'secs')
14+
sds011.read(READ_SECONDS);
1315
# esp.deepsleep(SLEEP_SECONDS * 1000000)

sds011.py

+23-20
Original file line numberDiff line numberDiff line change
@@ -35,38 +35,39 @@ def make_command(cmd, mode, param):
3535
tail = b'\xab'
3636
return header + cmd + mode + param + padding + bytes(checksum, 'utf8') + tail
3737

38-
def no_response():
38+
def confirm_response(confirmation):
3939
if (uart.read(1) == b'\xaa'):
4040
if (uart.read(1) == b'\xc5'):
41-
return False
42-
time.sleep_ms(500)
43-
return True
41+
print(confirmation)
4442

43+
# sensor wakes for 60 secs before issuing measurment
4544
def set_dutycycle(rest_mins):
4645
global uart
4746
cmd = make_command(CMDS['DUTYCYCLE'], CMDS['SET'], chr(rest_mins))
48-
while no_response():
49-
print('Setting sds011 to read every', rest_mins, 'minutes:', cmd)
50-
uart.write(cmd)
51-
print('sds011 duty cycle set!')
47+
print('Setting sds011 to read every', rest_mins, 'minutes:', cmd)
48+
uart.write(cmd)
49+
time.sleep_ms(1000)
50+
read(2)
5251

5352
def wake():
5453
global uart
5554
cmd = make_command(CMDS['SLEEPWAKE'], CMDS['SET'], chr(1))
56-
while no_response():
57-
print('Sending wake command to sds011:', cmd)
58-
uart.write(cmd)
59-
print('sds011 woke up!')
55+
print('Sending wake command to sds011:', cmd)
56+
uart.write(cmd)
57+
time.sleep_ms(12000)
58+
read(2)
6059

6160
def sleep():
6261
global uart
6362
cmd = make_command(CMDS['SLEEPWAKE'], CMDS['SET'], chr(0))
64-
while no_response():
65-
print('Sending sleep command to sds011:', cmd)
66-
uart.write(cmd)
67-
print('sds011 successfully put to sleep')
63+
print('Sending sleep command to sds011:', cmd)
64+
uart.write(cmd)
65+
time.sleep_ms(2000)
6866

69-
def process_packet(packet):
67+
def process_reply(packet):
68+
print('Reply received:', packet)
69+
70+
def process_measurement(packet):
7071
try:
7172
print('\nPacket:', packet)
7273
*data, checksum, tail = struct.unpack('<HHBBBs', packet)
@@ -88,17 +89,19 @@ def process_packet(packet):
8889

8990
def read(allowed_time=0):
9091
global uart
91-
print('Reading from sds011 for', (allowed_time / 1000), 'secs')
9292
start_time = time.ticks_ms()
9393
delta_time = 0
94-
while (delta_time <= allowed_time):
94+
while (delta_time <= allowed_time * 1000):
9595
try:
9696
header = uart.read(1)
9797
if header == b'\xaa':
9898
command = uart.read(1)
9999
if command == b'\xc0':
100100
packet = uart.read(8)
101-
process_packet(packet)
101+
process_measurement(packet)
102+
elif command == b'\xc5':
103+
packet = uart.read(8)
104+
process_reply(packet)
102105
delta_time = time.ticks_diff(time.ticks_ms(), start_time) if allowed_time else 0
103106
except Exception as e:
104107
print('Problem attempting to read:', e)

0 commit comments

Comments
 (0)