ODroid C2

As an owner of an Odroid C1+ that is a great little device, it came to my knowledge it it might now be obsolete :)

This is because the Odroid C2 has came out: Odroid C2, and if I think that the C1+ is great, what to tell about the C2, that is around the same price point?

The specifications:

64bit S905 ARM quad-core 2GHz processor
2GB of RAM !
HDMI 2.0 with 4K support (not that it matters for me… )
Gigabit Ethernet, as the C1+
eMMC support.
Several other tid bits very similar to C1+.
Missing RTC.

So a major leap forward from the C1+ and from the RPi.

The 40$ price in Europe is no near that value, but probably around 50/55€ mark, my guess ( + P/P). Also the eMMC prices are still very high, almost, or even higher, than the price of the board itself.

Still I’m a bit wary of buying one since HardKernel (the Odroid manufacturer) only provides a 4 week warranty !? I bought mine in Europe, so I suppose it has a 2 year warranty by law.

I had no problems with my C1+, but I wonder, if something goes wrong…

MQTT Dashboards

The freeboard.io dashboard is one of the most popular dashboards to build an interface for displaying data. Still, for supporting the MQTT protocol some configuration is needed that is not exactly straight forward. Also if don’t want to use MQTT but web sockets, a similar not straight forward configuration is also needed. After that configuration (MQTT support for freeboard.io and WebSocket support for freeboard.io) we can add MQTT and Web Sockets datasources to our dashboards, and we get a nice customable dashboard framework.

Anyway there are some nice alternatives available that are worth some attention for someone that wants a simpler way of doing things:

CroutonCrouton MQTT Dashboard
Node Red UINode-Red-ui

This dashboard is really nice since it has something that we might call as dashboard auto-configuration. We only need to configure the MQTT broker (with web sockets enabled, off course) and add device names to the configuration list. The device name is very important because it will be used in MQTT topic subscriptions (see below).

The Crouton dashboard configuration is stored on the browser local storage, so it’s not central. This means, that if you change browser or machine the configuration needs to be done again for that specific instance of browser and/or machine. Also, based on my experience, this is rather fidly, sometime it saves, other times it won’t, and need to reconfigure everything again after closing and opening the browser again.

The Crouton MQTT configuration is simple:

Crouton MQTT Configuration

MQTT Configuration

After the dashboard is connected to the MQTT broker, it searchs for specific topics based on the names configured on the Devices list. For each device it publishes to topic /inbox/devicename and subscribes to /outbox/devicename. At the initialization phase the Dashboard sends a get message to /inbox/devicename/deviceInfo. We can see that the device name is used to “find” a MQTT subscriber that answers to this topic. The subscriber that “owns” the topic /inbox/devicename answers to the get message with a JSON description of the device parameters to be shown at the dashboard on the /outbox/devicename/deviceInfo topic.

For example, on the following configuration:

Device Configuration

Device Configuration

The Crouton Dashboard sends to /inbox/Odroid/deviceInfo (Case Sensitive!!) and to /inbox/DiskStation/deviceInfo the message get and waits for a specific JSON response on /outbox/Odroid/deviceInfo and /outbox/DiskStation/deviceInfo to know how to automatically create the dashboard. With another words, the JSON response defines the dashboard. This means that to add a new metric, for example, we just need to add on the device the new metric and report it, no need to mess again with the dashboard configuration.

Auto Generated MQTT Dashboard

We can now use the mouse to move around the tiles, but the it seems also that this configuration isn’t stored.

This is the neat part of Crouton Dashboard, this auto-configuration.

The configuration is defined on the JSON response to /outbox/deviceName/deviceInfo MQTT topic. The JSON object defines the number of metrics and display format that device publishes and automatically associated to the metric name there is the MQTT topic /outbox/deviceName/Metric that the dashboard listens to.

On the Crouton GitHub there are two examples of this, one in Python and other in Lua for the ESP8266 NodeMCU based firmware.

I have a simpler one in Python, derived from the original Python example, for retrieving and send metrics from my Odroid SBC. The code is available here.

On the example note two things:

At the all.py file line 9, the clientName variable is set to Odroid. This is the device name to set on the Crouton dashboard.

Then for example, I publish my root disk space with the following JSON object segment:

        "endPoints": {
            "RootDisk": {
                "values": {
                    "labels": [],
                    "series": [0]
                "total": 100,
                "centerSum": true,
                "units": "%",
                "card-type": "crouton-chart-donut",
                "title": "Root Disk"

The above configuration means that the end point /outbox/Odroid/RootDisk will have some value published that should be shown as a doughnut chart with % units.

A bit below on the code, there is an infinite loop, that each 30 seconds publishes to the topic the available disk space in percentage:

   client.publish("/outbox/"+clientName+"/RootDisk" , '{"series":['+str(disk_usage(rootPath))+']}')

As a conclusion, this Dashboard is rather interesting and worth a look, even with it’s, for now, issues with saving the configuration.

While the Crouton Dashboard is an standalone Node.JS based application, the Node-Red-UI is an extension the Node-Red itself. It adds a new range of UI nodes to the Node-Red available nodes that allows to also build a Dashboard, but this time, not limited to MQTT. In fact any node that can inject data into a node-red-ui works.

The UI is available on the same address as Node-Red, but at the path /ui: Example:http://localhost:1880/ui/

For example, the following flow:

Node-Red-UI Flow

Node-Red-UI Flow

Generates the following UI:



The UI is based on the same MQTT topics and data published by my Crouton Python Client. The only thing needed is to extract the data from the MQTT message:

var space = msg.payload.series[0];
var msg ={"value":space , "payload":space};
return msg;

And the data feed from the “agents” work on both dashboards.

Anyway, regarding Node-Red-UI, it is an all other world, and I recommend to join and/or read the discussion group for this project.

Sming ESP8266 – Driving a 1.8 TFT ST7735 chip based display

The ST7735 display controller is one of the available display drivers found driving the 1.8 TFT 128×160 resolution display. This driver/TFT combo is found from several sources like Adafruit and eBay, and has software drivers for Arduino and other platforms.
Still these displays, despite the same name (1.8 TFT 128×160) can come with different controllers different from the ST7735 chip, like the Samsung S6D02A1 normally found on display labelled QDTech, and apparently there is also versions based on the ILI9163C chip.
Anyway I only have one of these displays and it’s based on the ST7735 chip and so here’s how I’ve connected and used a 1.8 TFT with 128×160 resolution the ESP8266 based ESP-12 board using the Sming Framework. The board needs to be an ESP-12 or other that exposes the ESP8266 SPI hardware pins, and so the ESP-01 is out of the question.

Why Sming framework?
The main reason is that I can use Netbeans and my build process without touching the Arduino IDE… Reason enough, I thing :)

The Adafruit ST7735 library
The latest Adafruit ST7735 Library supports the Arduino Boards and Teensy boards, and at compile time, specific code segments are enabled/disabled based on the target architecture. For example, when compiling to an Arduino the __AVR__ compiler time variable is defined. As far as I’m aware, this variable is also set when using the Arduino IDE when targeting the ESP8266 board, so no issues here.

The Sming framework defines the following compile time variable: __ESP8266_EX__, and we can just hack the library to support the Sming framework, or adapt it to be used on all or platforms. Anyway, my version is available here, and as far as my tests go, it works fine: Sming Adafruit ST7735 ESP8266.

The hardware connections:
The Library for the Sming framework uses the hardware SPI pins, so the connections should be the following:

Fixed pins SPI pins (can’t be changed)

  1. D13 – Serial data out -> MOSI/SDA
  2. D14 – Clock

Pins that can be changed and defined on the library constructor:

  1. D4 – CS -> Chip Select
  2. D5 – DC -> Data/Command

Also there is the reset pin from the display, that we can connect to an ESP8266 pin, like RST, for example, but I’ve just connected VCC (3.3v).

Based on this, my initialization code looks like:

#define TFT_CS    4
#define TFT_DC    5

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, 0);

// And on a main function after boot:
void startMain() {

    Serial.println("TFT Initialized");

    tft.drawLine(160, 12, 0, 12, ST7735_YELLOW);    
    cycle.initializeMs(2000, doScreen).start();

And that’s it.

Note: Notice that the examples extensively use the delay function, and that will make the ESP8266 to reboot.

Synology – Installing Python PIP package installer

A simple recipe for installing the pip utility that is needed to install Python packages/Modules:

1st) Install Python from the Package Installer Web interface. I have Python 2.7 installed

2nd) Connect to your Synology NAS through ssh.

3rd) Get the pip installer: wget https://bootstrap.pypa.io/get-pip.py

4th) Execute the installer: python get-pip.py. It will take a while:

 # python get-pip.py 
Collecting pip
  Downloading pip-8.0.2-py2.py3-none-any.whl (1.2MB)
    100% |████████████████████████████████| 1.2MB 42kB/s 
Collecting setuptools
  Downloading setuptools-19.6-py2.py3-none-any.whl (472kB)
    100% |████████████████████████████████| 475kB 109kB/s 
Collecting wheel
  Downloading wheel-0.26.0-py2.py3-none-any.whl (63kB)
    100% |████████████████████████████████| 65kB 291kB/s 
Installing collected packages: pip, setuptools, wheel
Successfully installed pip-8.0.2 setuptools-19.6 wheel-0.26.0

We can now execute the pip command:

# pip

  pip  [options]

  install                     Install packages.
  download                    Download packages.
  uninstall                   Uninstall packages.
  freeze                      Output installed packages in requirements format.
  list                        List installed packages.
  show                        Show information about installed packages.
  search                      Search PyPI for packages.
  wheel                       Build wheels from your requirements.
  hash                        Compute hashes of package archives.
  help                        Show help for commands.

Now we can install the modules that we need.

For example, installing paho-mqtt for MQTT support:

# pip install paho-mqtt
Collecting paho-mqtt
  Downloading paho-mqtt-1.1.tar.gz (41kB)
    100% |████████████████████████████████| 45kB 589kB/s 
Building wheels for collected packages: paho-mqtt
  Running setup.py bdist_wheel for paho-mqtt ... done
  Stored in directory: /var/services/homes/root/.cache/pip/wheels/97/db/5f/1ddca8ee2f9b58f9bb68208323bd39bb0b177f32f434aa4b95
Successfully built paho-mqtt
Installing collected packages: paho-mqtt
Successfully installed paho-mqtt-1.1

And we can use now the paho.mqtt module on our python programs.

ODroid – Mosquitto MQTT Broker install

Just for a quick reference, the following instructions detail how to install the latest Mosquitto MQTT broker with Websockets enabled on the ODroid C1+ running (L)Ubuntu release. The instructions are probably also valid for other platforms, but not tested.

1. Install the pre-requisits
As the root user, install the following libraries:

apt-get update
apt-get install uuid-dev libwebsockets-dev

Probably the SSL libraries, and a few others are also needed, but in my case they where already installed.

2. Mosquitto install
Download and compile the Mosquitto broker:

mkdir ~/mosq
cd ~/mosq
wget http://mosquitto.org/files/source/mosquitto-1.4.5.tar.gz
tar xvzf mosquitto-1.4.5.tar.gz
cd mosquitto-1.4.5/

Edit the config.mk file to enable the websockets support:

# Build with websockets support on the broker.

and compile and install:

make install

3. Configuration
Copy the file mosquitto.conf to /usr/local/etc, and edit the file:

cp mosquitto.conf /usr/local/etc
cd /usr/local/etc

Add at least the following lines to mosquitto.conf file to enable websockets support.

# Port to use for the default listener.
#port 1883
listener 1883
listener 9001
protocol websockets

Add an operating system runtime user for the Mosquitto daemon:

useradd -lm mosquitto
cd /usr/local/etc
chown mosquitto mosquitto.conf

If needed, or wanted, change also on the configuration file the logging level and destination.
For example:

# Note that if the broker is running as a Windows service it will default to
# "log_dest none" and neither stdout nor stderr logging is available.
# Use "log_dest none" if you wish to disable logging.
log_dest file /var/log/mosquitto.log

# If using syslog logging (not on Windows), messages will be logged to the
# "daemon" facility by default. Use the log_facility option to choose which of
# local0 to local7 to log to instead. The option value should be an integer
# value, e.g. "log_facility 5" to use local5.

# Types of messages to log. Use multiple log_type lines for logging
# multiple types of messages.
# Possible types are: debug, error, warning, notice, information, 
# none, subscribe, unsubscribe, websockets, all.
# Note that debug type messages are for decoding the incoming/outgoing
# network packets. They are not logged in "topics".
log_type error
log_type warning
log_type notice
log_type information

# Change the websockets logging level. This is a global option, it is not
# possible to set per listener. This is an integer that is interpreted by
# libwebsockets as a bit mask for its lws_log_levels enum. See the
# libwebsockets documentation for more details. "log_type websockets" must also
# be enabled.
websockets_log_level 0

# If set to true, client connection and disconnection messages will be included
# in the log.
connection_messages true

# If set to true, add a timestamp value to each log message.
log_timestamp true

4. Automatic start
The easiest way is to add the following file to the init.d directory and link it to the current runlevel:

Create the file named mosquitto under /etc/init.d


case "$1" in
        echo "Starting Mosquitto MQTT Broker"
        touch /var/log/mosquitto.log
        chown mosquitto /var/log/mosquitto.log
        su - mosquitto -c "/usr/local/sbin/mosquitto -c /usr/local/etc/mosquitto.conf" & > /dev/null 2>/dev/null
        echo "Stopping Mosquitto MQTT Broker"
        killall mosquitto
        echo "Usage: /etc/init.d/mosquitto start|stop"
        exit 1

exit 0

Find out the current run level. On Odroid it seems that is level 2:

root@odroid:/etc/init.d# runlevel
N 2

And link the automatic start for Mosquitto broker at run level 2:

cd /etc/rc2.d
ln -s  /etc/init.d/mosquitto S97mosquitto

And that’s it.

We can start manually the broker with the command /etc/init.d/mosquitto start, and stop it with the mosquitto stop command.

Synology DSM – Reverse Proxy (Part 2)

On my previous post Synology virtual sites for FileStation and others we could see how to create new sub domains under the main DNS name for your Synology to access the DSM applications like FileStation, Notes Station, and so on.

The configuration that is done creates a new full virtual site, on other words, all URL paths under the new sub domain are proxied to the redirected application. By other words, supposing that http://fs.domain.myds.me points to FileStation, all URL paths below to that URL are redirected to the FileStation site (for example http://fs.domain.myds.me/path1).

The following configuration is a bit different and it’s purpose is to redirect a URL path from the main site http://domain.myds.me to something else serving that path. For example, redirecting http://domain.myds.me/api to a backend Node.js REST server. The main reason to this is to allow Synology to host a site that uses, for example JQuery, or AngularJS, to also host the REST API that needs to be on the same domain due to the browser CORS protection. CORS protection means that a loading page from a site can only request data, by REST for example, from the origin web site. For example, my pages on http://domain.myds.me can call only REST services also on the same domain. It needs to be the same FQDN and PORT to the REST request be able to work. See more info at the Wikipedia page: Same-origin policy

And that’s because the above reason (CORS) that we need be able to proxy URL paths, and not full virtual sites, as the previous post as pointed out above.

To do this is quite simple, and the conditions are that the redirected path will be redirected from the main Synology user site.

So let’s redirect the path /api to a back end server:

Create a file named (for example) httpd-api-redirect.conf with the following content, replacing the backend_address and backend_port with the right information:

  ProxyPass http://backend_address:backend_port/api

Save this file at /etc/httpd/sites-enabled-user, and stop and restart the Apache server:

To stop the Web Station: /sbin/initctl stop httpd-user
To start the Web Station:  /sbin/initctl start httpd-user

After that accessing http://domain.myds.me should work as usual, but http://domain.myds.me/api should be redirected to the backend server.

And that’s it, we can now host JQuery and/or Angular sites that use REST services hosted on the Synology Apache server.

There also some caveats regarding this configuration, if serving another site, not a REST api, like the full/relative paths issue with the proxied site, and also, regarding REST, the use of the Accept-origin header. But for the simplest purpose of hosting the site and the REST api under the same domain name, this works fine.