Skip to content

Commit 7b802c9

Browse files
committed
lowpower: add mqtt_log.py, improve README.
1 parent f6152e3 commit 7b802c9

File tree

2 files changed

+113
-14
lines changed

2 files changed

+113
-14
lines changed

lowpower/README.md

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# A low power usayncio adaptation
22

3-
Release 0.12 15th April 2019
3+
Release 0.12 23rd April 2019
44

55
API changes: low power applications must now import `rtc_time_cfg` and set its
66
`enabled` flag.
@@ -75,12 +75,27 @@ tested. Copy the file `rtc_time.py` to the device so that it is on `sys.path`.
7575
very low power is consumed. A normally open pushbutton should be connected
7676
between `X1` and `Gnd`. This program is intended as a basic template for
7777
similar applications.
78+
* `howlow.py` A lower power version of the above. Polls the switch every 200ms
79+
rather than running debouncing code.
7880
* `lp_uart.py` Send and receive messages on UART4, echoing received messages
7981
to UART1 at a different baudrate. This consumes about 1.4mA and serves to
80-
demonstrate that interrupt-driven devices operate correctly.
82+
demonstrate that interrupt-driven devices operate correctly. Requires a link
83+
between pins X1 and X2 to enable UART 4 to receive data via a loopback.
84+
* `mqtt_log.py` A publish-only MQTT application for Pyboard D. See below.
8185

82-
The test program `lp_uart.py` requires a link between pins X1 and X2 to enable
83-
UART 4 to receive data via a loopback.
86+
`mqtt_log.py` requires the `umqtt.simple` library. This may be installed with
87+
[upip_m](https://github.com/peterhinch/micropython-samples/tree/master/micropip).
88+
```
89+
>>> upip_m.install('micropython-umqtt.simple')
90+
```
91+
This test is "experimental". Pyboard D support for low power WiFi is currently
92+
incomplete. I have seen anomolous results where power was low initially before
93+
jumping to ~30mA after a few hours. The application continued to run, but the
94+
evidence suggested that the WiFi chip was consuming power. See Damien's comment
95+
in [this issue](https://github.com/micropython/micropython/issues/4686).
96+
An option would be to shut down the WiFi chip after each connection. The need
97+
periodically to reconnect would consume power, but in applications which log at
98+
low rates this should avoid the above issue. Or wait for the firmware to mature.
8499

85100
###### [Contents](./README.md#a-low-power-usayncio-adaptation)
86101

@@ -135,11 +150,14 @@ loop = asyncio.get_event_loop()
135150
Latency(100) # Define latency in ms
136151
```
137152

138-
The `Latency` class has a continuously running loop that executes `pyb.stop`
139-
before yielding with a zero delay. The duration of the `stop` condition
140-
(`latency`) can be dynamically varied. If zeroed the scheduler will run at
141-
full speed. The `yield` allows each pending task to run once before the
142-
scheduler is again paused (if `latency` > 0).
153+
`Latency` is a functor: its only interface is with function call syntax, which
154+
takes a single argument being the `lightsleep` duration in ms. If the lowpower
155+
mode is in operation the first call instantiates a coroutine with a
156+
continuously running loop that executes `pyb.stop` before yielding with a zero
157+
delay. The duration of the `lightsleep` condition can be dynamically varied by
158+
further `Latency(time_in_ms)` calls. If the arg is zero the scheduler will run
159+
at full speed. The `yield` allows each pending task to run once before the
160+
scheduler is again paused (if the current latency value is > 0).
143161

144162
The line
145163
```python
@@ -392,16 +410,33 @@ async def bar():
392410

393411
the 10ms sleep will be >=200ms dependent on other application tasks.
394412

395-
Latency may be changed dynamically by using the `value` method of the `Latency`
396-
instance. A typical application (as in `lpdemo.py`) might wait on a "Start"
397-
button with a high latency value, before running the application code with a
398-
lower (or zero) latency. On completion it could revert to waiting for "Start"
399-
with high latency to conserve battery.
413+
Latency may be changed dynamically by issuing `Latency(time_in_ms)`. A typical
414+
application (as in `howlow.py`) might wait on a "Start" button with a high
415+
latency value, before running the application code with a lower (or zero)
416+
latency. On completion it could revert to waiting for "Start" with high latency
417+
to conserve battery. Logging applications might pause for a duration or wait on
418+
a specific RTC time with a high latency value.
419+
420+
Pyboard D users should note that firmware support for low power WiFi is
421+
incomplete. Consider turning off the WiFi chip when not in use:
422+
```
423+
sta_if = network.WLAN()
424+
while True:
425+
# Wait for trigger
426+
sta_if.active(True) # Enable WiFi
427+
sta_if.connect(SSID, PW)
428+
# Use the network
429+
sta_if.deinit() # Turns off WiFi chip
430+
```
431+
[ref](https://github.com/micropython/micropython/issues/4681)
400432

401433
###### [Contents](./README.md#a-low-power-usayncio-adaptation)
402434

403435
# 6. Note on the design
404436

437+
This module uses the old `pyb` in preference to `machine`. This is because the
438+
Pyboard 1.x `machine` module does not have an `RTC` class.
439+
405440
The `rtc_time` module represents a compromise designed to minimise changes to
406441
`uasyncio`. The aim is to have zero effect on the performance of applications
407442
not using `rtc_time` or ones running on non-Pyboard hardware.

lowpower/mqtt_log.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# mqtt_log.py Demo/test program for MicroPython asyncio low power operation
2+
# Author: Peter Hinch
3+
# Copyright Peter Hinch 2019 Released under the MIT license
4+
5+
# MQTT Demo publishes an incremental count and the RTC time periodically.
6+
# On my SF_2W board consumption while paused was 170μA.
7+
8+
# Test reception e.g. with:
9+
# mosquitto_sub -h 192.168.0.33 -t result
10+
11+
SERVER = '192.168.0.33' # *** Adapt for local conditions ***
12+
SSID = 'misspiggy'
13+
PW = '6163VMiqSTyx'
14+
15+
import rtc_time_cfg
16+
rtc_time_cfg.enabled = True
17+
18+
from pyb import LED, RTC
19+
from umqtt.simple import MQTTClient
20+
import network
21+
import ujson
22+
23+
import uasyncio as asyncio
24+
try:
25+
if asyncio.version[0] != 'fast_io':
26+
raise AttributeError
27+
except AttributeError:
28+
raise OSError('This requires fast_io fork of uasyncio.')
29+
from rtc_time import Latency
30+
31+
def publish(s):
32+
c = MQTTClient('umqtt_client', SERVER)
33+
c.connect()
34+
c.publish(b'result', s.encode('UTF8'))
35+
c.disconnect()
36+
37+
async def main(loop):
38+
rtc = RTC()
39+
red = LED(1)
40+
red.on()
41+
grn = LED(2)
42+
sta_if = network.WLAN()
43+
sta_if.active(True)
44+
sta_if.connect(SSID, PW)
45+
while sta_if.status() == 1:
46+
await asyncio.sleep(1)
47+
grn.toggle()
48+
if sta_if.isconnected():
49+
red.off()
50+
grn.on()
51+
await asyncio.sleep(1) # 1s of green == success.
52+
grn.off() # Conserve power
53+
Latency(2000)
54+
count = 0
55+
while True:
56+
publish(ujson.dumps([count, rtc.datetime()]))
57+
count += 1
58+
await asyncio.sleep(120) # 2 mins
59+
else: # Fail to connect
60+
red.on()
61+
grn.off()
62+
63+
loop = asyncio.get_event_loop()
64+
loop.run_until_complete(main(loop))

0 commit comments

Comments
 (0)