Batteriegestützte Internet-of-Things-Device: ESP8266 Wemos D1-mini Temperatursensor mit WLAN und MQTT

Ich habe für das ChaosBBQ einen kleinen Workshop vorbereitet, bei dem man sich ein kleines IoT-Device selbst zusammenlöten kann. Die Idee war, dass es möglichst lange mit einfachen Batterien läuft. Daher habe ich ein paar Aspekte darin verarbeitet, die im Umgang mit Internet-of-Things („Internet der Dinge“) häufig verwendet werden:

  • Wemos D1.mini, ein Breakout-Board mit dem ESP8266-Chip
  • Programmierung mit der Arduino IDE
  • Kommunikation mit WLAN
  • Protokoll MQTT zur Kommunikation mit einem MQTT-Broker, um die gemessenen Temperatur-Werte zu übermitteln

Hier der kurze Überblick über die benötigten Utensilien:

  • Wemos D1.mini
  • Stiftleisten (sind meistens mitgliefert
  • 4.7 kOhm Widerstand
  • Temperatursensor DS18B20
  • Batteriebox (alternativ auch eine 3er-Box aus Conrad/Völkner/Reichelt/….
  • Nicht abgebildet: Lötkolben, Lötzinn, etwas kleine Kabel

Hier der Wemos D1.mini im Detail:

Als Trick zum einfach festlöten der Stiftleisten steckt man am besten die reinen Leisten mit den reinen Stiften umgedreht in ein Breadboard:

Hier noch Kabel, Temperatursensor und der Widerstand:

Okay ein wenig Standard-Lötzinn braucht man zum Löten doch noch:

Die Stiftleisten auf den Wemos D1.mini anlöten:

Die zweite Seite ist eigentlich optional, da nur eine Seite für den Sensor verwendet wird. Aber da wir schon mal dabei sind…

Von der Batteriebox aus muss noch die Stromversorgung angelötet werden. Dazu den nun mit den Stiftbuchsen bestückten Wemos D1.mini im Breadboard belassen und bei „3V3“ den Pluspol und bei „G“ den Minuspol anlöten.

Sofern nicht-aufladbare Batterien verwendet werden (wie in diesem Beispiel), so sollte man die Gesamtspannung bei 3 Volt belassen. Daher den dritten Batteriehalter mit einem Stück Draht überbrücken (hier in weiß). Verwendet man stattdessen Akkus, so liefern diese jeweils nur 1.2 Volt je Zelle und daher werden insgesamt 3.6 Volt benötigt. Mit 2.4 Volt wollte der ESP8266 partout nicht starten…

Damit der ESP8266 aus dem DeepSleep, in den wir ihn später schicken wollen, sich auch selbst wieder aufwecken kann, benötigt dieser noch eine Drahtbrücke zwischen D0 und RST (hier in blau). WICHTIG: Zur Programmierung muss diese Drahtbrücke wieder entfernt werden, daher diese dafür entfernen und – ganz wichtig – die Verbindung NICHT LÖTEN.

Fehlt noch der Temperatursensor selbst und ein Widerstand. Der Temperatursensor sollte mit der flachen Seite zum Chip liegen. Dann gehört das linke Bein in D5, die Mitte in D6 und das rechte Bein in D7. Nachdem man den Sensor eingesteckt hat, wird noch ein Widerstand zwischen 3V3 und dem mittleren Bein, also D6 benötigt. Dieser fungiert als „Pull-Up“ und stellt damit die Protokollfähigkeit sicher. Sollte der Sensor öfter sehr merkwürdige Werte (z.B. -127 °C) liefern, ist wahrscheinlich der Widerstand etwas herausgerutscht.

Damit der Sensor seine Daten auch verschickt, brauchen wir noch ein Programm, welches wir mit der Arduino IDE auf den ESP8266 aufspielen. Hierzu beachten, dass unter „Boards“ auch der Wemos D1.mini ausgewählt ist.

Im nachfolgenden Programm müssen noch die WLAN-SSID, das WLAN-Passwort, die IP des MQTT-Servers und der Topic-„Pfad“ und ggf. der Topic-„Name“ geändert werden.

// Wemos D1 board, connected to a battery box and a DS18B20 temperature sensor
//
 
// For temperature reading
// Libraries needed:
// * OneWire
// * DallasTemperature
//
// Pinout: https://wiki.wemos.cc/products:d1:d1_mini
// D0 = GPIO16 --> Connect D0 to RST for Deep Sleep-Wakeup
 
#include <OneWire.h> 
#include <DallasTemperature.h>
 
const char* ssid = "ENTER_YOUR_SSID_HERE";
const char* password = "ENTER_YOUR_WLAN_PASS_HERE";
 
#define DEVICENAME "maintopic/devicename"
#define TOPIC DEVICENAME"/temperature"
#define ONLINETOPIC DEVICENAME"/online"
#define MQTTSERVER IPAddress(37, 187, 106, 16) // test.mosquitto.org = 37.187.106.16
const int sleepTimeS = 300; // Reduce this value for debugging. Increase if you want more battery life
 
#define VCCPIN D7
#define ONE_WIRE_BUS D6
#define GNDPIN D5
 
OneWire oneWire(ONE_WIRE_BUS); 
DallasTemperature sensors(&oneWire);
 
float tempC;
 
// For WLAN & MQTT
#include <ESP8266WiFi.h>
#include <AsyncMqttClient.h>
AsyncMqttClient mqttClient;
uint16_t packetId1Pub;
bool packet1Ack = false;
 
bool ready = false;
 
char *ftoa( double f, char *a, int precision)
{
 long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
 
 char *ret = a;
 long heiltal = (long)f;
 itoa(heiltal, a, 10);
 while (*a != '\0') a++;
 *a++ = '.';
 long desimal = abs((long)((f - heiltal) * p[precision]));
 itoa(desimal, a, 10);
 return ret;
}
 
void onMqttPublish(uint16_t packetId) {
  Serial.println("** Publish acknowledged **");
  Serial.print("  packetId: ");
  Serial.println(packetId);
  // TODO: Only when both packages were acknowledged...
  if (packetId == packetId1Pub) {
    packet1Ack = true;
  }
  if (packet1Ack) {
    ready = true;
  }
}
 
void onMqttConnect(bool sessionPresent) {
  char buf[7];
  packetId1Pub = mqttClient.publish(TOPIC, 1, true, ftoa(tempC, buf, 2));
}
 
 
void setup() {
  pinMode(GNDPIN, OUTPUT);
  pinMode(VCCPIN, OUTPUT);
  digitalWrite(GNDPIN, LOW);
  digitalWrite(VCCPIN, HIGH);
  Serial.begin(115200); 
  Serial.println("ESP-Temperature-Reader-and-MQTT-Poster-via-WiFi"); 
  // Start up the sensors library 
  sensors.begin(); 
}
 
void loop() {
  // Send the command to get temperature readings 
  Serial.println("Requesting Temperature"); 
  sensors.requestTemperatures();
 
  // You can have more than one DS18B20 on the same bus.  
  // 0 refers to the first IC on the wire 
  Serial.println("Requesting Temperature from Device 0"); 
  tempC = sensors.getTempCByIndex(0);
 
Serial.println("Connecting to WIFI"); 
  // Connect to WiFi
  WiFi.begin(ssid, password);
  int timeout = 0;
  while (WiFi.status() != WL_CONNECTED) {
    timeout++;
    if (timeout>20) {
        // WIFI isn't available after 10 seconds -> abort mission, mission's a failure
        initiateDeepSleep();
      }
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
 
  // Print the IP address
  Serial.println(WiFi.localIP());
 
  // Publish result to MQTT
  mqttClient.onConnect(onMqttConnect);
  mqttClient.onPublish(onMqttPublish);
  mqttClient.setServer(MQTTSERVER, 1883);
  mqttClient.setKeepAlive(5).setCleanSession(false).setWill(ONLINETOPIC, 2, true, "no"); // .setCredentials("user", "pass").setClientId(DEVICENAME);
  Serial.println("Connecting to MQTT...");
  mqttClient.connect();
 
  timeout = 0;
  while (!ready) {
    delay(250);
    timeout++;
    if (timeout > 40)
    {
        // MQTT isn't available after 10 seconds -> abort mission, mission's a failure
        initiateDeepSleep();
    }
    Serial.print(".");
  }
  Serial.println("");
  initiateDeepSleep();
}
 
void initiateDeepSleep()
{
  ESP.deepSleep(sleepTimeS * 1000000);
  delay(100); 
}

Die Gesamtpräsentation mit allen Informationen von dieser Webseite könnt ihr hier auch noch herunterladen:

IoT Temperatursensor Präsentation ODP

IoT Temperatursensor Präsentation PDF

Using hybrid DVB-T/DVB-C-Stick with Linux, disabling the first frontend (frontend0)

I only wanted the DVB-C-Part of my stick (dvb_usb_rtl28xxu), but after VDR access the first frontend of this device (/dev/dvb/adapter0/frontend0), the device won’t be accessible on its other frontend (/dev/dvb/adapter0/frontend1), so I had to find a way to disable the first frontend.

If you have trouble scanning any channels, please take a look at you dmesg whether there was a problem loading the correct firmware. For me it looked like this:

user@host:~# dmesg | grep firmware
[23945257.415086] mn88473 7-0018: Direct firmware load for dvb-demod-mn88473-01.fw failed with error -2

Your firmware is most certainly somewhere in the github directory of OpenELEC: https://github.com/OpenELEC/dvb-firmware/tree/master/firmware

For example, I had to copy the dvb-demod-mn88473-01.fw to /lib/firmware/:

sudo wget https://github.com/OpenELEC/dvb-firmware/raw/master/firmware/dvb-demod-mn88473-01.fw -O /lib/firmware/dvb-demod-mn88473-01.fw

Check whether w_scan works:

sudo w_scan -fc -c DE >>dvb-c-channels.conf

Search for the DEVPATH of the frontend which you want to disable (for me it was adapter0/frontend0):

user@host:~# udevadm info --query=all --name=/dev/dvb/adapter0/frontend0 | grep DEVPATH
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb3/3-4/dvb/dvb0.frontend0

Then add a new udev-rule as a new file /etc/udev/rules.d/11-disable-frontend0.rules:

ACTION=="add", SUBSYSTEM=="dvb", ENV{DVB_DEVICE_TYPE}=="frontend", DEVPATH=="/devices/pci0000:00/0000:00:14.0/usb3/3-4/dvb/dvb0.frontend0", ENV{dynamite_attach}="no"

I must admit that this didn’t work for me. I had to move the frontend0 manually to a higher number, disabling it by this for vdr:

user@host:~# mv /dev/dvb/adapter0/frontend0 /dev/dvb/adapter0/frontend9

VDR auf Server kompilieren, Einbindung von IPTV und Steuerung über KODI auf einem Client

Server mit Netzwerkanschluss hinter einem T-Entertain-Anschluss. An den Fernsehern im Haus liegt bereits Netzwerk und jeweils ein Raspberry PI oder ähnliches, um als Empfänger des VDR-Streams zu agieren. Auf den Clients läuft ein KODI (teilweise unter OpenELEC), welcher die Integration des VDR erleichtern soll. Es steckt allerdings keine DVB-T/DVB-C-Karte oder ähnliches im Server, sondern er soll die IPTV-Streams von der Telekom (T-Entertain/T-Home) nutzen. Dieses Vorgehen ist völlig legal. Einziger Nachteil bei dieser Vorgehensweise: Es gibt praktisch keine EPG-Daten aus dem Datenstrom, diese sind – bis auf „now“ und „next“ – verschlüsselt und können nur durch den von der Telekom bereitgestellten „Media Receiver“ entschlüsselt werden.

Der VDR wurde hierfür selbst kompiliert, um die notwendigen Plugins direkt nutzen zu können. Da es einige Zeit und Nerven gekostet hat, eine vernünftige Lösung hierfür zu finden, ist hier ein Skript zu finden, welches die vorausgesetzten Pakete installiert, alles herunterlädt und kompiliert.

#!/bin/bash
 
# Work directory
### Warning: This script installs the resulting vdr to /work/vdr, yes, this is on the root level!
MYCURRENTDIR="${PWD}"
cd /work/vdr
 
#####
## Install prerequisites
#####
sudo apt-get install build-essentials dialog libcap-dev libjpeg62-dev libfreetype6{,-dev} fontconfig{,-config} libfontconfig1{,-dev} libcurl4-gnutls-dev libcxxtools-dev libtntnet-dev
 
#####
## Changes these if newer versions are available (and these work)
#####
CURRVDRVER="2.2.0"
CURRIPTVVER="2.2.1"
CURRDIR="$(pwd)"
 
#####
## Download everything which we don't already have
#####
 
if [ ! -e vdr-${CURRVDRVER}.tar.bz2 ]; then
        wget -O vdr-${CURRVDRVER}.tar.bz2 ftp://ftp.tvdr.de/vdr/vdr-${CURRVDRVER}.tar.bz2
fi
 
if [ ! -d vdr-${CURRVDRVER} ]; then
        tar xvfj vdr-${CURRVDRVER}.tar.bz2
        ln -s /work/vdr/vdr-${CURRVDRVER} /work/vdr/vdr
fi
 
if [ ! -e vdr-iptv-${CURRIPTVVER}.tgz ]; then
        wget -O vdr-iptv-${CURRIPTVVER}.tgz http://www.saunalahti.fi/~rahrenbe/vdr/iptv/files/vdr-iptv-${CURRIPTVVER}.tgz
fi
 
if [ ! -d vdr-${CURRVDRVER}/PLUGINS/src/iptv ]; then
        mkdir -p vdr-${CURRVDRVER}/PLUGINS/src/iptv
        tar xvfz vdr-iptv-${CURRIPTVVER}.tgz -C vdr-${CURRVDRVER}/PLUGINS/src/iptv --strip-components=1
fi
 
#####
## Further Plugins
#####
 
### VNSI
# https://github.com/FernetMenta/vdr-plugin-vnsiserver
if [ ! -d vdr-${CURRVDRVER}/PLUGINS/src/vdr-plugin-vnsiserver ]; then
        cd vdr-${CURRVDRVER}/PLUGINS/src
        git clone https://github.com/FernetMenta/vdr-plugin-vnsiserver
        ln -s vdr-plugin-vnsiserver vnsiserver
        cd /work/vdr
fi
 
### epgsearch (needed for VDR Live)
# http://winni.vdr-developer.org/epgsearch/downloads/vdr-epgsearch-1.0.0.tgz
if [ ! -e vdr-plugin-epgsearch-2.2.0.tgz ]; then
        wget -O vdr-plugin-epgsearch-2.2.0.tgz https://projects.vdr-developer.org/git/vdr-plugin-epgsearch.git/snapshot/vdr-plugin-epgsearch-2.2.0.tar.gz
fi
 
if [ ! -d vdr-${CURRVDRVER}/PLUGINS/src/epgsearch ]; then
        mkdir -p vdr-${CURRVDRVER}/PLUGINS/src/epgsearch
        tar xvfz vdr-plugin-epgsearch-2.2.0.tgz -C vdr-${CURRVDRVER}/PLUGINS/src/epgsearch --strip-components=1
fi
 
### VDR Live
# http://live.vdr-developer.org/downloads/vdr-live-0.3.0.tar.gz
if [ ! -e vdr-plugin-live-release_0-3-0.tgz ]; then
        wget -O vdr-plugin-live-release_0-3-0.tgz https://projects.vdr-developer.org/git/vdr-plugin-live.git/snapshot/vdr-plugin-live-release_0-3-0.tar.gz
fi
 
if [ ! -d vdr-${CURRVDRVER}/PLUGINS/src/live ]; then
        # mkdir -p vdr-${CURRVDRVER}/PLUGINS/src/live
        # tar xvfz vdr-plugin-live-release_0-3-0.tgz -C vdr-${CURRVDRVER}/PLUGINS/src/live --strip-components=1
  cd /work/vdr/vdr-${CURRVDRVER}/PLUGINS/src
        git clone https://projects.vdr-developer.org/git/vdr-plugin-live.git/
  mv /work/vdr/vdr-${CURRVDRVER}/PLUGINS/src/vdr-plugin-live /work/vdr/vdr-${CURRVDRVER}/PLUGINS/src/live
fi
 
cd /work/vdr
 
#### Autotimer
# http://phivdr.dyndns.org/vdr/vdr-autotimer/vdr-autotimer-2.3.0.tgz
if [ ! -e vdr-autotimer-2.3.0.tgz ]; then
        wget -O vdr-autotimer-2.3.0.tgz http://phivdr.dyndns.org/vdr/vdr-autotimer/vdr-autotimer-2.3.0.tgz
fi
 
if [ ! -d vdr-${CURRVDRVER}/PLUGINS/src/vdr-autotimer ]; then
        mkdir -p vdr-${CURRVDRVER}/PLUGINS/src/autotimer
        tar xvfz vdr-autotimer-2.3.0.tgz -C vdr-${CURRVDRVER}/PLUGINS/src/autotimer --strip-components=1
fi
 
#####
## Compile
#####
 
cd /work/vdr/vdr-${CURRVDRVER}
# Das CXXFLAGS="-std=gnu++03" wird benoetigt, da das iptv-Plugin mit den neuen Makros nicht klar kommt (-std=gnu11)
CXXFLAGS="-std=gnu++03" make -j $(grep -c ^processor /proc/cpuinfo)
cd ..
 
# channels.conf (loading these from a forum where someone listed all channels...)
if [ ! -e channels.conf ]; then
  preString = "pre" # Workaround for wordpress-blogpost, it would end the code otherwise
  wget -O - -q  http://www.vdr-portal.de/board16-video-disk-recorder/board5-vdr-konfiguration/119211-iptv-t-home-entertain-channels-conf-aktuelle-eintr%C3%A4ge/ | grep "\(IPTV:\|</${prestring}>\)" | sed '1,1d; /<\/pre>/,$d' >channels.conf
fi
cd /work/vdr/vdr-${CURRVDRVER}
rm channels.conf
ln -s ../channels.conf channels.conf
 
mkdir -p video
mkdir -p resources
mkdir -p cache
 
# Webinterface
sudo ln -s /work/vdr/vdr/PLUGINS/src/live/live/css /work/vdr/vdr-2.2.0/resources/plugins/live/
sudo ln -s /work/vdr/vdr/PLUGINS/src/live/live/img /work/vdr/vdr-2.2.0/resources/plugins/live/
sudo ln -s /work/vdr/vdr/PLUGINS/src/live/live/js /work/vdr/vdr-2.2.0/resources/plugins/live/
sudo ln -s /work/vdr/vdr/PLUGINS/src/live/live/themes /work/vdr/vdr-2.2.0/resources/plugins/live/
 
# setup.conf initial
## sudo rm /work/vdr/vdr-${CURRVDRVER}/setup.conf
 
# iptv configuration
# 15.07.2014: Sollte der VDR die IPTV Kanäle mit der CAID "4AE2" versehen, im iptv-Plugin "Deaktiviere Filter: 1 (PAT 0x00)" definieren und Einträge bereinigen
sudo bash -c "cat <<EOF >>setup.conf
iptv.DisabledFilters = 1
EOF
"
 
# vnsiserver configuration
sudo mkdir -p /media/tv
 
sudo bash -c "cat <<EOF >>setup.conf
vnsiserver.Timeshift = 2
vnsiserver.TimeshiftBufferDir = /media/tv
vnsiserver.TimeshiftBufferFileSize = 20
vnsiserver.TimeshiftBufferSize = 30
EOF
"
 
 
# vnsiserver access rights
# sudo cat >/work/vdr/vdr-${CURRVDRVER}/plugins/vnsiserver/allowed_hosts.conf <<EOF
sudo bash -c "cat <<EOF >/work/vdr/vdr/plugins/vnsiserver/allowed_hosts.conf
#
# allowed_hosts.conf  This file describes a number of host addresses that
#                     are allowed to connect to the streamdev server running
#                     with the Video Disk Recorder (VDR) on this system.
# Syntax:
#
# IP-Address[/Netmask]
#
 
127.0.0.1             # always accept localhost
192.168.6.0/24        # any host on the local net
#204.152.189.113      # a specific host
#0.0.0.0/0            # any host on any net (USE THIS WITH CARE!)
EOF
"
 
# Plugins
cd PLUGINS/lib
rm *
 
find ../ -iname '*.so' -exec ln -s {} . \;
for file in *.so; do mv ${file} $(echo ${file} | sed "s/\.so/.so.${CURRVDRVER}/") ; done
 
cd ../..
 
echo "Starting VDR"
cd ..
echo "Going back to ${MYCURRENTDIR}"
cd "${MYCURRENTDIR}"
 
./run.sh

And for run.sh, I used this:

#!/bin/bash
cd /work/vdr/vdr && sudo /work/vdr/vdr/vdr --log=3 -v /data/Videos/TV -c . -L /work/vdr/vdr/PLUGINS/lib --plugin=iptv --localedir=/work/vdr/vdr/locale --resdir=/work/vdr/vdr/resources --cachedir=/work/vdr/vdr/cache -P'vnsiserver -t 5' -P'epgsearch' -P'live'

Mining Monero on old Ubuntu

Getting the xmr-stak-cpu to work on an ubuntu 14.04:

* Compile gcc from scratch and install to /home/user/inst (script)

#!/bin/bash
VER=7.1.0
cd
WORKDIR=${PWD}/work/gcc-${VER}
INSTDIR=${WORKDIR}/inst
mkdir -p ${WORKDIR}
mkdir -p ${INSTDIR}
cd ${WORKDIR}
if [ ! -e gcc-${VER}.tar.bz2 ]; then
	wget -O gcc-${VER}.tar.bz2 ftp://ftp.gwdg.de/pub/misc/gcc/releases/gcc-${VER}/gcc-${VER}.tar.bz2
fi
if [ ! -e gcc-${VER} ]; then
	tar xvfj gcc-${VER}.tar.bz2
fi
cd gcc-${VER}
./contrib/download_prerequisites
# 64bit only
./configure --disable-multilib --prefix=/home/user/inst && make -j $(grep -c ^processor /proc/cpuinfo) && make install

* Compile cmake from scratch

cd
mkdir -p work
cd work
mkdir -p cmake
cd cmake
wget https://cmake.org/files/v3.8/cmake-3.8.2.tar.gz
tar xvfz cmake-3.8.2.tar.gz
cd cmake-3.8.2.tar.gz
./configure --prefix=/home/user/inst && make && make install

* Download the xmr-stak-cpu files and compile

mkdir -p $HOME/work/xmr
cd $HOME/work/xmr
git clone https://github.com/fireice-uk/xmr-stak-cpu
cd xmr-stak-cpu
CC=$HOME/inst/bin/gcc CXX=$HOME/inst/bin/g++ PATH=$HOME/inst/bin:$PATH cmake . -DCMAKE_INSTALL_PREFIX=$HOME/xmr-stak-cpu -DMICROHTTPD_REQUIRED=OFF && make && make install

This will compile the file with the new gcc and the new cmake. The result will be installed to $HOME/xmr-stak-cpu, it’s only the executable file and the config.txt.

To run, you must point your LD_LIBRARY_PATH to the correct directory, otherwise you’ll get strange errors:

LD_LIBRARY_PATH="$HOME/inst/lib64" ./xmr-stak-cpu

Arduino als JTAG Programmer

Ich würde gerne meine Honeywell Heizkörperregler HR-20 Rondostat zeitgesteuert nicht nur passiv auslesen (das geht auch schon mit der nativen Firmware), sondern auch über einen ESP8266 steuern. Das wurde schon von schlauen Leuten vorgedacht, und daher gibt es mit OpenHR20 auch eine neue Firmware, welche man mittels JTAG-Interface auf das HR20 flashen kann.

Ich habe nur kein JTAG-Programmierer zur Hand, aber dafür einen Arduino Uno. Ich habe den Ansatz eines JTAGduino gefunden. Die notwendigen Lötarbeiten waren schnell erledigt, ich habe die nachfolgende Steckerbelegung (Quelle) berücksichtigt, um den JTAGduino zu versorgen. Um eine durchgehende Stiftleiste am Arduino Uno verwenden zu können, habe ich die gesamte Kommunikation auf die Analogen Ports A0 bis A4 gelegt.

Die ersten Tests mit den von JTAGduino mitgelieferten Skripten verliefen erfolgreich, wenn ich das JTAG-Interface vom Arduino an den HR20 angeschlossen habe und mein Arduino an meinen Linux-Rechner per USB verbunden ist, kommt folgende Ausgabe:

user@host:~/work/JTAGduino$ ./host_test.py 
if_ver_major = 0; if_ver_minor = 1
fw_ver_major = 0; fw_ver_minor = 1
set_serial_speed(115200) = 0
clear pin TDI rsp = 1
set pin TDI rsp = 0
get pin TDO rsp = 0; val = 0
jtag_clock(1,1): rsp = 1; tdo = 0
jtag_clock(1,0): rsp = 0; tdo = 1
jtag_sequence([1,1,1,1], [1, 1, 0, 1]), rsp = 0; tdo_seq = [1, 0, 0, 0]
jtag_sequence([1] * 255, [1] * 255), rsp = 0; tdo_seq = [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
device.set_jtag_speed(1) = 255
jtag_sequence([1] * 255, [1] * 255), rsp = 127; tdo_seq = []
user@host:~/work/JTAGduino$ ./readid.py 
Traceback (most recent call last):
  File "./readid.py", line 81, in 
    if rsp != 0: raise Exception('error: set_jtag_speed returned %d' % rsp)
Exception: error: set_jtag_speed returned 191
user@host:~/work/JTAGduino$ ./readid.py 
#Taps = 1
Device identifier registers (beginning from closest to TDO):
0x6940503F

Die Fehlermeldung habe ich absichtlich drin gelassen, damit man auch andere den Grund für den Fehler finden können. Man muss vor JEDEM Ansprechen des JTAGduino diesen manuell auf durch einen Druck auf den Reset-Button am Arduino zurücksetzen.

Die ID 0x6940503F ist bereits die vom HR20, wir können also grundsätzlich per JTAG bereits mit ihm kommunizieren.

Als nächstes muss ich noch herausfinden, wie avrdude mit dem so gebauten „Programmer“ sprechen kann, bisher habe ich nur ermitteln können, dass es eine mögliche Liste von Programmern in avrdude vordefiniert gibt: (Der Pfad zur Arduino-Installation muss natürlich angepasst werden)

user@host:~/work/JTAGduino$ PATH=$PATH:/arduino-1.8.1/hardware/tools/avr/bin avrdude -c dslfkj -C /arduino-1.8.1/hardware/tools/avr/etc/avrdude.conf 2&lt;&amp;1 | grep -i jtag
  atmelice         = Atmel-ICE (ARM/AVR) in JTAG mode (avrdude: jtag3_open_common(): JTAGICE3/EDBG port names must start with "usb")
  dragon_jtag      = Atmel AVR Dragon in JTAG mode
  jtag1            = Atmel JTAG ICE (mkI)
  jtag1slow        = Atmel JTAG ICE (mkI)
  jtag2            = Atmel JTAG ICE mkII
  jtag2avr32       = Atmel JTAG ICE mkII im AVR32 mode
  jtag2dw          = Atmel JTAG ICE mkII in debugWire mode
  jtag2fast        = Atmel JTAG ICE mkII
  jtag2isp         = Atmel JTAG ICE mkII in ISP mode
  jtag2pdi         = Atmel JTAG ICE mkII PDI mode
  jtag2slow        = Atmel JTAG ICE mkII
  jtag3            = Atmel AVR JTAGICE3 in JTAG mode
  jtag3dw          = Atmel AVR JTAGICE3 in debugWIRE mode
  jtag3isp         = Atmel AVR JTAGICE3 in ISP mode
  jtag3pdi         = Atmel AVR JTAGICE3 in PDI mode
  jtagkey          = Amontec JTAGKey, JTAGKey-Tiny and JTAGKey2
  jtagmkI          = Atmel JTAG ICE (mkI)
  jtagmkII         = Atmel JTAG ICE mkII
  jtagmkII_avr32   = Atmel JTAG ICE mkII im AVR32 mode
  o-link           = O-Link, OpenJTAG from www.100ask.net (avrdude: Error: no libftdi or libusb support. Install libftdi1/libusb-1.0 or libftdi/libusb and run configure/make again.)
  xil              = Xilinx JTAG cable (tested - avrdude: can't claim device "/dev/ttyACM0": Inappropriate ioctl for device)
  xplainedpro      = Atmel AVR XplainedPro in JTAG mode

Den nachfolgenden Befehl nutze ich zum Test, ob der jeweilige Programmer-Typ funktioniert, er sollte bei erfolgreicher Kommunikation nur Backups von fuses anlegen, also führt noch keine schreibenden Operationen aus:

user@host:~/work/JTAGduino$ PATH=$PATH:/arduino-1.8.1/hardware/tools/avr/bin avrdude -p m169 -c xil -P /dev/ttyACM0 -C /arduino-1.8.1/hardware/tools/avr/etc/avrdude.conf -U lfuse:r:backup/unknown/`date  "+%F_%T"`/lfuse.hex:h -U hfuse:r:backup/unknown/`date  "+%F_%T"`/hfuse.hex:h -U efuse:r:backup/unknown/`date  "+%F_%T"`/efuse.hex:h

So wie es aussieht, ist die Library nicht komplett, und für meinen Anwendungszweck vielleicht gar nicht geeignet. Ich bin dadurch über eine JTAG-Library gestoßen, welche man direkt über die Arduino-IDE nachinstallieren kann: https://github.com/mrjimenez/JTAG

Nach dem Upload des JTAGTest-Programms (wird als Beispiel in der ArduinoIDE bereitgestellt, wenn man die Bibliothek installiert hat) auf dem Arduino kann man das python-Programm „xsvf“ nutzen, um erste Tests durchzuführen:

user@host:~/work/JTAG/extras/python$ ./xsvf ../xsvf/all/idcode_simpler.xsvf
File: /work/JTAG/extras/xsvf/all/idcode_simpler.xsvf
Ready to send 18 bytes.
Sent:       18 bytes,        0 remaining
IMPORTANT: ********
IMPORTANT: Success!
IMPORTANT: ********
IMPORTANT: Last TDO: FF FF FF FF/32 bits
IMPORTANT: Processed 5 instructions.
IMPORTANT: Checksum:  0xC2/18.
IMPORTANT: Sum: 0x0000003E/18.
Quit: No error (0).
  Expected checksum:  0xC2/18.
  Expected sum: 0x0000003E/18.
Elapsed time: 0.02 seconds.

Mit der neuen JTAG-Library alle möglichen Programmiermodi des avrdude durchgegangen:

atmelice         = Atmel-ICE (ARM/AVR) in JTAG mode (avrdude: jtag3_open_common(): JTAGICE3/EDBG port names must start with "usb")
  dragon_jtag      = Atmel AVR Dragon in JTAG mode (no response)
  jtag1            = Atmel JTAG ICE (mkI) (avrdude: jtagmkI_open(): failed to synchronize to ICE)
  jtag1slow        = Atmel JTAG ICE (mkI) (avrdude: jtagmkI_open(): failed to synchronize to ICE)
  jtag2            = Atmel JTAG ICE mkII (no response)
  jtag2avr32       = Atmel JTAG ICE mkII im AVR32 mode (avrdude: jtagmkII_recv_frame(): timeout     avrdude: jtagmkII_getsync(): sign-on command: status -1)
  jtag2dw          = Atmel JTAG ICE mkII in debugWire mode
  jtag2fast        = Atmel JTAG ICE mkII
  jtag2isp         = Atmel JTAG ICE mkII in ISP mode
  jtag2pdi         = Atmel JTAG ICE mkII PDI mode
  jtag2slow        = Atmel JTAG ICE mkII
  jtag3            = Atmel AVR JTAGICE3 in JTAG mode
  jtag3dw          = Atmel AVR JTAGICE3 in debugWIRE mode
  jtag3isp         = Atmel AVR JTAGICE3 in ISP mode
  jtag3pdi         = Atmel AVR JTAGICE3 in PDI mode
  jtagkey          = Amontec JTAGKey, JTAGKey-Tiny and JTAGKey2
  jtagmkI          = Atmel JTAG ICE (mkI)
  jtagmkII         = Atmel JTAG ICE mkII
  jtagmkII_avr32   = Atmel JTAG ICE mkII im AVR32 mode
  o-link           = O-Link, OpenJTAG from www.100ask.net (avrdude: Error: no libftdi or libusb support. Install libftdi1/libusb-1.0 or libftdi/libusb and run configure/make again.)
  xil              = Xilinx JTAG cable (avrdude: can't claim device "/dev/ttyACM0": Inappropriate ioctl for device)
  xplainedpro      = Atmel AVR XplainedPro in JTAG mode (avrdude: jtag3_open_common(): JTAGICE3/EDBG port names must start with "usb")

 

Arduino als Audio-Aufnahmequelle

Ich habe einen der Mikrofon-Sensoren ergattert, die man für Arduino bzw. Raspberry Pis günstig erwerben kann. Meiner war in einem „37 in 1“-Sensor-Kit enthalten. Schließt man diesen direkt mit A0 an den Arduino an, erhält man allerdings keine sinnvollen Werte, insbesondere weichen diese kaum von 2.5V Eingang ab. Die prinzipielle Schaltung lässt aber auf „D0“ das High bzw. Low erkennen, der Sensor selbst funktioniert also.

Um sinnvoll damit arbeiten zu können, musste ich zunächst einmal den Ausgang entkoppeln, dafür habe ich einen kleinen Kondensator (4.7 uF) angeschlossen. Das aus dem A0-Anschluss dieses Mikrofon-Breakouts erhaltene Signal ist nur zu schwach, muss also deutlich verstärkt werden. Ich habe einen MAX406 gefunden, der herumlag. Mit 470 Ohm als Vorwiderstand und 100 kOhm als Widerstand zwischen IN- und OUT sollte eine etwa 25-fache-Verstärkung herauskommen.

Das Signal aus dem Mikrofon komm ebenfalls an IN-, an IN+ habe ich GND angeschlossen.

Mit einem Piezo-Lautsprecher angeschlossen an GND und PIN9 vom Arduino Uno und das verstärkte Eingangssignal an A0 kann man nun gute das „Knackern“ hören, was vorher nur ein unangenehmes Piepsen war. Im seriellen Output kann man gut nachvollziehen, dass von der Schwallwelle nur eine Seite der Welle verstärkt wird, die andere ist praktisch immer Null und somit kommt auch noch nicht wirklich etwas verständliches heraus. Immerhin sind einfach Testtöne (Sinus-Wellen) darüber schon zu erkennen.

Ein möglicher nächster Schritt wäre nun:

Über einen (einstellbaren) Spannungsteiler die Referenzspannung, die an IN+ gegeben wird, zu verkleinern. Ferner muss das Eingangssignal durch einen 1:1-Spannungsteiler geschickt werden, um dann bei „keinem“ Signal etwa 50% Ausgangssignal zu liefern und dies dann beim Arduino wieder herauszurechnen. So würde das Signal vollständig verstärkt werden.

WinPCap in eigenem .NET-Programm verwenden

Den letzten „Developer’s Pack“ von WinPCap herunterladen:

http://www.winpcap.org/devel.htm

Auspacken und die Location merken, wo die Dateien nun liegen.

Wrapper herunterladen:

https://github.com/PcapDotNet/Pcap.Net/tree/master

Am einfachsten hierzu das aktuelle Repository als ZIP-Datei herunterladen und entpacken:

https://github.com/PcapDotNet/Pcap.Net/archive/master.zip

In dem ausgepackten Pfad diese Solution öffnen:

Pcap.Net-master\PcapDotNet\src\PcapDotNet.sln

  • Auf „Release“ umstellen
  • Auf „x64“ umstellen
  • PcapDotNet.Core -> Rechtsklick -> Eigenschaften
    • VC++ Directories
      • Include Directories: Den Pfad vom WpdPack\Include hinzufügen
      • Library Directories: Den Pfad von WpdPack\Lib\x64 hinzufügen
  • Alles kompilieren (Das Target Framework muss identisch mit dem im nächsten Schritt verwendeten sein)

Testweise etwas kompilieren:

Pcap.Net-master\PcapDotNet.DevelopersPack\src\PcapDotNet.DevelopersPack.sln öffnen

Bei „ObtainingTheDeviceList“ muss man die References anpassen, die Pfade müssen auf die „Relase“-Zweige der oben erstellten DLLs zeigen.

Das Resultat sollte ein Kommandozeilenfenster mit „1. rpcap://\Device…“ sein.

Export EV3 from Lego Digital Designer

Recently I created a complex LEGO model with Lego Digital Designer and wanted to import the resulting model into Blender. My export files were missing the LEGO Mindstorms EV3-components that I had added.

The reason for this behaviour are the missing parts in the ldraw.xml-File, which is in the same directory as the ldd.exe, the directory C:\Program Files (x86)\LEGO Company\LEGO Digital Designer held this file for me.

The ldraw.xml is essentially a mapping file, which maps all the LEGO-internal structures to the more open „LDRAW“-File format. The EV3-parts weren’t listed and even in updated ldraw.xml-Files, which I could find on the web, these were never added.

So I created the missing mappings on my own and the result works pretty good. Not all the colours are correct, but I couldn’t find an easy way to correct these.

Here are the necessary steps to successfully export LEGO EV3-parts from Lego Digital Designer and import these with correct colours e.g. into Blender:

  1. Copy ldraw.xml file to your location of ldd.exe, overwrite the old ldraw.xml. (Unzip the ldraw.zip to ldraw.xml first)
  2. Export your model from Lego Digital Designer to „LDraw-Files (*.ldr)“-format.
  3. Open the file in notepad++, search for the following part numbers (they are located at the end of the line) and change the BEGINNING of the line from „1 71“ to „1 15“.
    • Example:
      • 1 71 -90.175277709960937 -176.40634155273437 -275.99981689453125 0 1.0000001192092896 0 0 0 1.0000001192092896 1.0000001192092896 0 0 95658.dat
      • 1 15 -90.175277709960937 -176.40634155273437 -275.99981689453125 0 1.0000001192092896 0 0 0 1.0000001192092896 1.0000001192092896 0 0 95658.dat
    • Do this for all lines with these part numbers (not all might be in your file, only if you have added the corresponding EV3-bricks):
      • 95650.DAT
      • 95658.DAT
      • 95648.DAT
      • 99455.DAT
  4. Import the corrected file in LeoCAD and export into „Wavefront (.obj)“
  5. Open Blender and follow these instructions to get a first decent result:
    1. File -> Import -> Wavefront (.obj)
    2. Select -> Select all by Type -> Mesh
    3. Press „s“ (SCALE) and enter a value (blind, there is no dialog box), e.g. „0.1“ and hit return. Or you resize with your mouse after pressing „s“.
    4. Right-click and hold on the camera in blender, and move it around to where you want it to be.
    5. Check your current view by hitting the „0“ on your numpad. (This will change to the camera view)
    6. Right-Click during camera view on the border of the camera (it will turn orange), and then right-click and hold outside the camera view to tilt for your needs.
    7. Add some lights via Add -> Lamp -> Area  (or Sun) and position them.
    8. Render by pressing F12
    9. In the render-menu on the right hand side you can change the size of the resulting image, e.g. „Preset: HDTV 1080p“.
    10. By pressing F3 the rendered image is stored to your disc. (Current used path is at the bottom of the render-menu, defaults to /tmp.)

KODI: Spinup HDD when Screensaver was deactivated

When trying to access my recordings on my NAS, kodi seems to stop working for a short while when the NAS realizes that it is being accessed and starts spinning up the discs. I figured that it would be nice for the NAS to spin up earlier, if the screen saver of a „connected KODI“ is deactivated.

After enabling the JSON-RPC-TCP 9090-Port on Kodi (In System/Settings/Network/Services activate „Allow programs on this system to control Kodi for localhost access only“ and „Allow programs on other systems to control Kodi for access from other computers as well“), this script should be run at boottime on the NAS. Make sure to replace the accessed discs with your /dev/sdX-entries on your system. Also replace HOSTNAME with the host which as Kodi running, if the discs are in use on the same host, replace it with „localhost“.

The command must be run as root.

onidlespinupdiscs.sh:

#!/bin/bash
# Must be run as root
while true
do
  netcat -d HOSTNAME 9090 | (
    cnt=0
    line=
    while read -N 1 c; do
      line="$line$c"
      if [ "$c" = "{" ]; then
        cnt=$((cnt+1))
      elif [ "$c" = "}" ]; then
        cnt=$((cnt-1))
        if [ $cnt -eq 0 ]; then
          printf "%s\n" "$line"
          line=
        fi
      fi
    done
  ) | while read line
  do
    match=$(echo ${line} | grep -c "GUI.OnScreensaverDeactivated")
    if [ $match -eq 1 ]; then
      dd if=/dev/sdb bs=4096 count=1 of=/dev/null iflag=direct >/dev/null 2>&1 &
      dd if=/dev/sdc bs=4096 count=1 of=/dev/null iflag=direct >/dev/null 2>&1 &
    fi
  done
  sleep 60
done

Disable all LEDs and network LEDs on Raspberry Pi 2 with OpenELEC

I’m using OpenELEC on a Raspberry Pi 2, but the LEDs, especially those of the network device, are WAY too bright and keep distracting people when watching TV. The LEDs which are onboard of the RPi2 can be disabled with two simple commands (see below), but the network lights are much brighter and can’t be disabled by default.

I found a website which was written in portoguese, which offered a patch for this problem. The patch didn’t work with the current OpenELEC-release, so I had to modify it a bit.

Simply put, the patch adds a new functionality to the driver for the network interface smsc95xx.c, by creating three sysfs-entries.

Here is the modified patch, to apply it, you have to git clone the current OpenELEC-github-Repository and copy the patch to this directory: /OpenELEC.tv/packages/linux/patches/

File linux-999-disable-network-lights.patch:

--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -74,6 +74,8 @@
 module_param(turbo_mode, bool, 0644);
 MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
 
+int smsc95xx_ledctl(struct usbnet *dev);
+
 static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
                                            u32 *data, int in_pm)
 {
@@ -1024,6 +1026,9 @@
        if (ret < 0)
                return ret;
 
+       // Init sysfs led controller
+       smsc95xx_ledctl(dev);
+
        /* Init Tx */
        ret = smsc95xx_write_reg(dev, FLOW, 0);
        if (ret < 0)
@@ -2023,3 +2028,87 @@
 MODULE_AUTHOR("Steve Glendinning <steve.glendinning@shawell.net>");
 MODULE_DESCRIPTION("SMSC95XX USB 2.0 Ethernet Devices");
 MODULE_LICENSE("GPL");
+
+/*
+ * Led control patch
+ */
+
+static struct usbnet *leddev = NULL;
+
+static ssize_t smsc95xx_store(struct class *cls, struct class_attribute *attr, const char *buf, size_t count);
+static ssize_t smsc95xx_show(struct class *cls, struct class_attribute *attr, char *buf);
+
+static CLASS_ATTR(eth_fdx,S_IWUSR, smsc95xx_show, smsc95xx_store);
+static CLASS_ATTR(eth_lnk,S_IWUSR, smsc95xx_show, smsc95xx_store);
+static CLASS_ATTR(eth_spd,S_IWUSR, smsc95xx_show, smsc95xx_store);
+
+int smsc95xx_ledctl(struct usbnet *dev){
+
+    int ret = 0;
+    static struct class led_gpio = {
+
+        .name = "smsc95xx_leds",
+    };
+
+    if(leddev != NULL) return 0;
+
+    leddev = dev;
+
+    ret = class_register(&led_gpio);
+    if(ret){
+        leddev = NULL;
+        return ret;
+    }
+
+    ret += class_create_file(&led_gpio,&class_attr_eth_fdx);
+    ret += class_create_file(&led_gpio,&class_attr_eth_lnk);
+    ret += class_create_file(&led_gpio,&class_attr_eth_spd);
+
+    if(ret){
+        leddev = NULL;
+        class_unregister(&led_gpio);
+        return ret;
+    }
+
+    return 0;
+}
+
+static ssize_t smsc95xx_show(struct class *cls, struct class_attribute *attr, char *buf){
+
+return scnprintf(buf, PAGE_SIZE, "you can't even read");
+}
+
+
+static ssize_t smsc95xx_store(struct class *cls, struct class_attribute *attr, const char *buf, size_t count){
+int ret = 0;
+static u32 write_buf = LED_GPIO_CFG_FDX_LED |
+                       LED_GPIO_CFG_LNK_LED |
+                       LED_GPIO_CFG_SPD_LED;
+
+
+    if(buf[0] == '0'){
+
+        switch(attr->attr.name[6]){
+
+            case 'x': write_buf ^= LED_GPIO_CFG_FDX_LED; break;
+            case 'k': write_buf ^= LED_GPIO_CFG_LNK_LED; break;
+            case 'd': write_buf ^= LED_GPIO_CFG_SPD_LED; break;
+        }
+
+    }else if(buf[0] == '1'){
+
+        switch(attr->attr.name[6]){
+
+            case 'x': write_buf |= LED_GPIO_CFG_FDX_LED; break;
+            case 'k': write_buf |= LED_GPIO_CFG_LNK_LED; break;
+            case 'd': write_buf |= LED_GPIO_CFG_SPD_LED; break;
+        }
+    }
+
+    ret = smsc95xx_write_reg(leddev, LED_GPIO_CFG, write_buf);
+
+    if(ret < 0) netdev_warn(leddev->net,"Failed to write LED_GPIO_CFG: %d\n",ret);
+
+    return 1;
+}
+

If the file is correctly copied, you can start to build the image, this will take some time:

PROJECT=RPi2 ARCH=arm make image

Copy the new image to a fresh sd-card and insert it into the RPi2. After boot, connect to ssh (you have to enable the sshd via the on-screen menu which you will see at the beginning) and add a new file, called autostart.sh to the ~/.config/ directory:

autostart.sh

#!/bin/bash
 
# Turn off system LEDs
echo none > /sys/class/leds/led0/trigger
echo 0 > /sys/class/leds/led0/brightness
 
echo none > /sys/class/leds/led1/trigger
echo 0 > /sys/class/leds/led1/brightness
 
# Turn of network LEDs
echo 0 > /sys/class/smsc95xx_leds/eth_fdx
echo 0 > /sys/class/smsc95xx_leds/eth_lnk
echo 0 > /sys/class/smsc95xx_leds/eth_spd

UPDATE:

As I wanted to keep my existing configuration and the IR-support, I wanted to compile the Openelec-Branch for the 7.0 version.

git clone https://github.com/OpenELEC/OpenELEC.tv.git
cd OpenELEC.tv
git checkout openelec-7.0
cp ../linux-999-disable-network-lights.patch packages/linux/patches/4.4.45/
PROJECT=RPi2 ARCH=arm make image