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).

GPIO

 

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 () { 
    console.log(state); 
    if (state) led.writeSync(0) 
    else led.writeSync(1); 
    state = ! state; 
    } 
} 
 
f=blinkled7(); 
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');

button.watch(function (err, value) {
  if (err) {
    throw err;
  }
  console.log("Changing to ", value);
  led.writeSync(value);
});

process.on('SIGINT', function () {
  console.log("Leaving...");
  led.unexport();
  button.unexport();
});

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!

 

LED’s

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.

PWM

Not figured out yet.

 

Nov 062016
 

During today’s Dev Japan Meetup I finally had the time to do something I always wanted to do but never had time to implement: Create a fast link from an end-device (AKA browser or phone application) to my LED display. That display is a simple 10×10 WS2812 LEDs strip originally connected to an Arduino with a Bluetooth receiver, but replaced by a Wemos D1 mini flashed with Espruino since that has WiFi and more RAM.

Here the important (but incomplete) part of the Espruino program:

var host = "the_ws_server.co.jp";
var WebSocket = require("ws");
var ws = new WebSocket(host,{
  path: '/',
  port: 8080, // default is 80
  protocol : "echo-protocol", // websocket protocol name (default is none)
  protocolVersion: 13, // websocket protocol version, default is 13
  origin: 'Espruino',
  keepAlive: 60
});

ws.on('open', function() {
  console.log("Connected to server");
});

ws.on('message', function(msg) {
  console.log("MSG: " + msg);
  if (msg == "R") {
    colorize(40, 10, 10);
  } else if (msg == "G") {
    colorize(10, 40, 10);
  } else if (msg == "B") {
    colorize(10, 10, 40);
  }
  esp8266.neopixelWrite(NodeMCU.D4, leds);
});

The logic is as simple as it looks: connect to a WS server and wait for incoming messages. If it’s “R”, or “G”, or “B”, then colorize the LED array.

Here a section of the browser part:

var ws = new WebSocket("ws://the_ws_server.co.jp:8080/");

ws.onopen = function(evt) {
  var conn_status = document.getElementById('conn_text');
  ws.send(JSON.stringify({"join":"led"}));
};

ws.onmessage = function(evt) {
  var newMessage = document.createElement('p');
  newMessage.textContent = "Server: " + evt.data;
  document.getElementById('messages_txt').appendChild(newMessage);
};

ws.onclose = function(evt) {
  alert ("Connection closed");
};

$(".color").click(function(evt) {
  console.log($(this).attr("val"));
  ws.send(JSON.stringify({"room":"led","msg":$(this).attr("val")}));
});

and the buttons look like

<button type="submit" class="color" val="R">Red</button>
<button type="submit" class="color" val="G">Green</button>
<button type="submit" class="color" val="B">Blue</button>

The one missing part is the websocket server in the middle which relays messages, which I took quite literally from here from the Espruino Websocket docs.

This is anything but clean code, and not yet a complete and instructive example application, but it’s the first step and a good proof-of-concept.

Next step is a web page to have a 10×10 grid of buttons which can be turned on/off by touching, and the corresponding commands are sent to the LED display.

Oct 162016
 
Node-RED: Functions

My light sensor (actually just a LDR connected to the single ADC pin on the ESP8266) tends to be a bit jumpy and the graphs looked anything but smooth. Quick fix: averaging samples. Node-RED has functions for this. And here is one to average 4 samples:

// jshint esversion: 6

const oldDataMax=4;
let lastData;
let count = context.get('count')||0;
let oldData = context.get('oldData')||[];

// Need to shift all numbers one left if array full
// Circular buffer would be nice, but overly complex for such small buffers

if (count==oldDataMax) {
 for (let i=1; i<oldDataMax; ++i) {
 oldData[i-1]=oldData[i];
 }
 lastData=oldDataMax-1;
} else {
 lastData=count++; 
}
oldData[lastData]=parseInt(msg.payload);

// Calculate the average

let avg=0;
for (let i=0; i<=lastData; ++i) {
 avg+=oldData[i];
 }
avg=avg/(lastData+1);

context.set('count', count);
context.set('oldData', oldData);

let avgMsg = { payload: ""+avg };

return [ msg, avgMsg ];

Much less jumpy graphs now!

 

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
ds18b20.setup(gpio0)

# plot temp over time

mytime0 = tmr.time()
n = 0

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

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 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 https://github.com/haraldkubota/rgbled-websocket

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)
      value=10*value+c.charCodeAt()-48;

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

 

Apr 302016
 
My Lifx Bulbs - Resurrected

Some time ago (2013? 2014?) I ordered 2 Lifx bulbs: WiFi connected LED lamps did sound awesome to have. The software resp. firmware was unfortunately flakey (connecting to WiFi took many tries, and occasionally it stopped responding to WiFi). There was also no official API. In the end, it was a pair of unreliable lamps. They worked fine as “dump lamps” though. Last year I tried again, and the software and firmware improve, but I had no lamp that could handle the weight (about 300g).

However, I checked last week and the software improved: new firmware 2.0 available. And plenty APIs documented and plenty connectivity to cloud services. Worth to have another look at those Lifx bulbs.

So I bought a nice clamp light which has no issue with the weight (and a very strong clamp).

The Android app (version 3.5) works. Connecting to the bulk was still a hit-and-miss, but after 3 tries all worked. New firmware is now on both bulbs with the promise that further firmware updates won’t take 30min… we’ll see.

The more fun part is programming the bulbs to do things like “Wake me up in the morning”. I took this as a challende to program in node.js as I imagined a command (for Linux of course) would be too easy (cron+command=done).

There a neat lifx library for node.js available here which was a very good start. Took several attempts to understand how it works, but once it made ‘click’, it was straightforward. And reliable too. Kudos to Marius for the nice library. My result is here and while small, I’m happy about the result.

And because it’s running on node.js, it works on my little fanless ARM Linux machines too.

Dec 312015
 
Synology git

Running git on github is great, but since all repositories are public, there’s a certain danger to publish password, API keys or similar on it. See here.

Since I got a Synology NAS, I can install a git server package! Except it does not do a lot, but it’s enough to get started and have my repositories on NAS. One central location. One location where making a backup is much easier than on random devices.

Requirements for this to work:

  • Enable ssh access on the NAS
  • Have a home directory with .ssh and .ssh/authorized_keys so you can log in via ssh and without needing to enter a password

Now to set up a git repository:

  • Install the git server Synology package
  • Log in as root on the NAS
  • cd /volumeX (x=1 in my case since I have only one volume)
    mkdir git-repos ; chown YOURACCOUNT:users git-repos
  • Log in as you on the NAS
  • cd git-repos
    mkdir dockerstuff; cd dockerstuff ; git init --bare --shared ; cd ..
  • Repeat for other repositories/directories

Now on a git client do:

  • git clone ds.lan:/volume1/git_repos/dockerstuff
  • put files in here
  • git add * ; git commit -a -m "Initial population" ; git push