Dec 182016
Orange Pi Zero - I/O

I finally figured out how to do simple I/O on the GPIO pins on the Orange Pi Zero. It’s actually the same as Raspberry Pi and it relies on /sys/class/gpio/

Most important: Use Armbian, and I in particular use 3.4.113 (legacy).



Linux GPIO SOC Label CON4 CON4 Label SOC Linux GPIO
Vcc3V3-EXT 1 2 DCIN-5V
12 PA12 TWI0-SDA 3 4 DCIN-5V
11 PA11 TWI0-SCK 5 6 GND
6 PA6 PWM1 7 8 UART1_TX PG6 198
GND 9 10 UART1_RX PG7 199
1 PA1 UART2_RX 11 12 PA7 PA7 7
0 PA0 UART2_TX 13 14 GND
3 PA3 UART2_CTS 15 16 TWI1-SDA PA19  19
VCC3V3-EXT 17 18 TWI1-SCK PA18 18
15 PA15 SPI1_MOSI 19 20 GND
16 PA16 SPI1_MISO 21 22 UART2_RTS PA2 2
14 PA14 SPI1_CLK 23 24 SPI1_CS PA13 13
GND 25 26 PA10 PA10?

Note: PA10 does not seem to work.


To enable one GPIO pin, do this as root:

echo 7 >/sys/class/gpio/export
chmod a+rw /sys/class/gpio/gpio7/*

Now in NodeJS you can do (as non-root):

var Gpio = require('onoff').Gpio, 
  led = new Gpio(7, 'out'); 
function blinkled7() { 
  var state=false; 
  return function () { 
    if (state) led.writeSync(0) 
    else led.writeSync(1); 
    state = ! state; 
setInterval(f, 1000);

which blinks GPIO pin 7 (AKA PA7). You can also watch pins:

var Gpio = require('onoff').Gpio,
  led = new Gpio(7, 'out'),
  button = new Gpio(16, 'in', 'both'); (err, value) {
  if (err) {
    throw err;
  console.log("Changing to ", value);

process.on('SIGINT', function () {

which makes the LED match what PA16 is. If you connect PA16 to e.g. PA6, you can change PA6, which is detected by PA16 which is reflected in the LED change on PA7!



The 2 on-board LED’s can be controlled via

echo [0|1] > /sys/class/leds/[red|green]_led/brightness

which map to PA17 (red) and PL10 (green), but those are (of course) claimed by the LED driver.


Not figured out yet.


Dec 032016

Since I keep forgetting what pins I used for the ‘595 ICs which drive my 16 segment LED clock, here the pinout:

1: Vcc   2: GND
3: /SCK  4: NC
5: SER   6: NC
7: /RCK  8: NC
9:      10: NC

Since it’s HC595, Vcc is 2 up to 6V

And while on this topic, the 16 segment has this order when sending a 16 bit stream:


Bit 0 is t, bit 15 is a.

Nov 192016
Orange Pi Zero - Neat

Got myself a (actually two) Orange Pi Zero: US$7, quad core ARM Cortex A7@1.2GHz, 256MB RAM, WLAN, FastEthernet, 1 USB, USB-to-go for power. All in a (about) 5×5 cm² package. Add in a 8GB microSD card, and it’s a small capable little board.

While the memory looks on the small side, itś plenty to run one program. Armbian uses about 40MB itself when running:

harald@opz1:~$ free 
              total        used        free      shared  buff/cache   available 
Mem:         247012       36720      142740        2168       67552      193175 
Swap:        131068           0      131068

leaving >200MB left. Given that I can have a (small, limited) web server runnig on an ESP8266 with about 40KB RAM, 256MB is plenty for a single-purpose server/controller.

Ethernet works (as expected). WLAN works via simple nmtui command.

Controlling the 2 LED’s is easy too:

root@opz1:/# cd /sys/class/leds/red_led 
root@opz1:/sys/class/leds/red_led# ls 
brightness  device  max_brightness  power  subsystem  trigger  uevent 
root@opz1:/sys/class/leds/red_led# echo 1 >brightness  

That turns on the red LED. Similar for the green LED.

To find out what GPIO’s exist, use this:

root@opz1:/sys/class/leds/red_led# cat /sys/kernel/debug/gpio                                              
GPIOs 0-383, platform/sunxi-pinctrl, sunxi-pinctrl: 
 gpio-10  (?                   ) out hi 
 gpio-17  (red_led             ) out hi 
 gpio-202 (xradio_irq          ) in  lo 
 gpio-354 (?                   ) out hi 
 gpio-362 (green_led           ) out hi

To export a GPIO, do

# echo 15 >/sys/class/gpio/export

and then in /sys/class/gpio/gpio15/ you can see the standard Linux kernel GPIO things like direction (in/out) and value (0/1)

See also the schematics which show what port of the H2+ connects to what thing: orange-pi-zero-schanetics-v1_11 (sp!)


Oct 302016

Lua is neat, but learning Lua and JavaScript and NodeJS. Although Lua and especially NodeMCU is similar (not only in name) to NodeJS, it would be nicer to use only one language.

Here the recipe:

  1. Download espruino_1v87.tve_master_b3dc05b_esp8266.tgz
  2. Write flash (note: might use 80m and qio, but my old one does dio):
    ./ --port /dev/ttyUSB0 --baud 115200 write_flash --flash_freq 40m --flash_mode dio --flash_size 32m \
    0x0000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/boot_v1.6.bin \
    0x1000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/espruino_esp8266_user1.bin \
    0x3FC000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/esp_init_data_default.bin \
    0x37E000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/blank.bin
  3. Verify it:
    ./ --port /dev/ttyUSB0 --baud 115200 verify_flash \
    0x1000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/espruino_esp8266_user1.bin \
    0x3FC000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/esp_init_data_default.bin \
    0x37E000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/blank.bin
  4. Connect at 115200bps.
  5. Connect to your AP:
    var wifi = require("Wifi");
    wifi.connect("your_sid", {password:"your_password"}, function(err){
     console.log("connected? err=", err, "info=", wifi.getIP());
  6. In the Espruino IDE add the IP address
  7. When you reconnect via Espruino IDE, you should now have 2 choices: serial or TCP/IP via WLAN


Sep 222016

I bought a small waterproof DS18B20 based temperature probe. Finally I had a reason to use it: to measure the temperature drop in the joeveo mug which I received 2 days ago. While the theory is sound, it’s one thing to just believe in it or to measure yourself. I pick the latter, especially if it it involves some programming!

Temperature over time for various things

x: time in seconds, y: temperature in degrees Celsius

Using flot (for now) to make a quick graph, I got a sense of temperature drop in my normal ceramic mug as well as an idea of the drop in an insulation mug. The first graph (ice melting in glass) was using integers for the temperature.  The DS18B20 can clearly do better, so the next measurements I did with the floating point NodeMCU firmware.

Here the trivial code:

ds18b20 = require("ds18b20")
gpio0 = 3

# plot temp over time

mytime0 = tmr.time()
n = 0

function plot_temp()
 uart.write(0, "["..tmr.time()-mytime0..",""],")
 n = n > 4 and 0 or n+1
 if n == 0 then

tmr.alarm(0, 10000, tmr.ALARM_AUTO, plot_temp)

Integrate the output into a HTML et voilà: a simple yet good looking graph.

Step 2 is to actually measure the temperature in the joeveo mug.


Aug 202016
Power Usage of Wemos D1 mini + WS2812B RGB Shield

Using the Wemos D1 mini + WS2812B RGB shield + Battery shield and a 750 mAh single cell LiPo from my Walkera Dragonfly V120D02S , I wondered how long it’ll last to run. It’s not super-low power (use Bluetooth for that, not Wifi), but anything from 1h to 24h was possible according to my estimates and absolute power rating limits. So it’s time to measure!

The conditions:

  • ws-to-tcp bridge in my PC bridges the raw TCP port with a WebSocket port which is what the JavaScript web page uses which can change the LED color.
  • Lua program runs listening on a TCP socket. Nothing else runs actively.
  • When a command comes in via the TCP socket, analyze the command and execute it. Estimated run time: less than 10ms.
  • To confirm all keeps on working, I changed the LED color about 4 times per hour.
  • The LED was set to run at 20% R, G and B (brightness 55 out of 256).
  • The set of battery shield, D1 mini and LED shield and the battery had no other connections to the outside world.


  • Run time: 14h (750mAh LiPo from fully charged via battery shield, to 3.45V)
  • Average power draw for the LiPo: 700mAh/14h=50mA (assuming 700mAh used)
  • Assuming 90% efficiency of the DC-DC circuit (see TP5410 datasheet), that’s about 30mA@5V coming out of the battery shield (it only feeds +5V)
  • Average power consumption by LED: 55/256*3*20mA=13mA@5V (plus whatever the LED controller chip uses)
  • Leaving 17mA for the D1 mini. The LDO RT9013 drops that to 3.3V (still 17mA)
  • No sleep mode was used here since the device is listening to a TCP port.

The efficiencly is obviously improvable (going from >3.3V to 5V and then to 3.3V again for the ESP8266).

Side note: Charging is taking about 1h until the call has 4.195V. Very nice. I’ll see what the cell voltage is when the TP5410 shuts down. According to the data sheet, it’s likely 2.7V (undervoltage protection).

Update a day later:

With the WS2812 LED being on with low intensity, here the result:

  • Run time: 20h
  • Voltage of LiPo: 2.7V at the end
  • The TP5410 of the battery shield turned off 5V, but the 5V rail still had voltage to make the red and green LEDs of the WS2812 glow (blue turned off)
  • The ESP8266 was still rsponsive via WiFi. Its blue WiFi LED got significantly fainter compared to before when the LiPo was full.
  • Using the same assumptions as above:
    • 21mA@5V out of the TP5410
    • LED board: <1mA @ 5V, for the LEDs
    • About 20mA for the D1 mini module

This is consistent with the first measurement and good enough for me. For a day of being online, you need 1Ah single cell LiPo for the CPU/battery module.

This list shows 15mA for Modem Sleep State and 50mA and more for active WiFi connections. The conclusion would be that NodeMCU uses Modem Sleep when listening to incoming TCP packets.

Aug 142016

When you have a microcontroller which can connect to the network and it has a RGB LED, the logical step is to make this LED controllable via a web browser.

The list of issues faced is numerous:

  • NodeMCU does not handle websockets natively
  • Thus a bridge between normal TCP sockets used by NodeMCU and WebSockets used by the web browser is needed: ws-tcp-bridge does that
  • ws-tcp-bridge defaults to binary blobs which the browser cannot handle. Switching the websocket’s binaryType to arraybuffer fixes this
  • Sending data too fast to a just created websocket which has its binaryType not yet changed to arraybuffer breaks ws-tcp-bridge with a fatal error:
    TypeError: “list” argument must be an Array of Buffers
  • NodeMCU uses Lua, the browser JavaScript. The langages are quite similar! See below for an example.

Code is at

Interesting is the comparison of Lua and JavaScript variable names are the same):

JavaScript Lua
for (c of s.split('')) {

  if (c>='0' && c<='9') {
    if (state==1)

    } else {
      if (state==1) {
        setOneColor(color, value);
      if (c=='R' || c=='G' || c=='B') {
for n=1,s:len(),1 do
   c=s:sub(n, n)
   if c>='0' and c<='9' then
     if state==1 then
     if state==1 then
       setOneColor(color, value)
     if c=='R' or c=='G' or c=='B' then


Aug 132016

2 more I/O shields: Temperature and humity sensor (DHT22 AKA AM2302) and here the super-simple example:

0 26 1 800 0

That’s 26.8 °C and 1.0% humidity. I somehow don’t trust the humidity…

And here the push button module example, which shows well how much the contact bounce is:

 local pin=3
 gpio.mode(pin, gpio.INT, gpio.PULLUP)
 local pulse1=0

 local function pushed(level)
 local pulse2 =
 print("Level: ", level, "since last change: ", pulse2-pulse1, " ns")
 gpio.trig(pin, "down", pushed)