Alle Artikel von starcalc

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

Minimal-Arduino selbst bauen: Bootloader auf ATMEGA328P-PU

Zunächst einmal braucht man für die Programmierung der ATMEGA328P-PU einen „normalen“ Arduino. Ich habe mir bei ebay für wenig Geld aus Hong Kong einen Arduino-Klon besorgt. Es handelte sich dabei um einen „Pro.mini.328P“ („New Pro Mini atmega328 Board 5V 16M Arduino Compatible Nano NEW“). Das Gerät war ohne USB-Header ausgestattet, also musste ich zunächst noch einen USB-Serial-Wandler hierfür nutzen. Diesen hatte ich schon, er stammte ebenfalls aus Hong Kong.

Nachdem RX vom USB-Wandler zum TX vom mini Pro verbunden wurden, musste noch TX<->RX, 5V<->VCC und GND<->GND verbunden werden. Die „Blink“-Demo sollte laufen.

Danach die Blink-Demo in der Arduino-Programmierumgebung laden und testweise auf den Ardunio laden. Blinkt die Diode nun im (neu) vorgegebenen Takt, hat alles geklappt. Die Voraussetzung für die eigentliche Programmierung ist jetzt gegeben.

Nun kann man sich grob weiter an dem Artikel der make-Redaktion entlanghangeln: http://www.heise.de/make/artikel/Arduino-Uno-als-In-System-Programmer-2769246.html

Übrigens: Um das AVRDUDE unter Windows zu nutzen, lädt man sich das Open Source-Programm von hier: http://download.savannah.gnu.org/releases/avrdude/avrdude-6.1-mingw32.zip

Als nächsten Schritt muss der Pro.mini.328P zu einem ISP-Programmer gemacht werden. Hierzu lädt man in der Arduino-IDE unter „Beispiele“ den Sketch „Ardunio ISP“ aus und lädt diesen hoch.

Die Verkabelung muss danach wie folgt aussehen (den 10kOhm-Widerstand am Pin 1 kann man auch weglassen).

BreadboardAVR

Der Quarz muss wirklich gut verbunden sein, sonst erhält man fortlaufend nur Fehlermeldungen der Art:

avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x36
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x36
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x36
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x36
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x36
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x36
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x36
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x36
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x36
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x36

Und man sollte beim als ISP verwendeten Arduino nicht vergessen, zwischen GND und RESET einen 10 Micro-Farad-Kondensator einzusetzen, da dieser sonst immer wieder zurückgesetzt wird.

In der Arduino-IDE den ZIEL-Arduino auswählen (Hier: ATMEGA328P-PU = Arduino Uno) und als Programmer auf „ArduinoISP“ umstellen. Dann kann man mit „Bootloader brennen“ hoffentlich das blinken des Arduinos sehen und nach wenigen Sekunden ist der Bootloader fertig gebrannt. Da ich hiernach eine Menge unnötiger Zeit mit einer Fehlersuche vertan hatte, hier noch der wichtige Tipp, dass man den Quell-Arduino (den man als ISP einsetzt) am Ende, also nach fertigem Brennen noch einmal in den RESET schickt. Aus irgendeinem Grund hatte bei mir der ATMEGA328P sonst in einer Breadboard-Anordnung keinerlei Anstalten gemacht, das Bootloader-Blinken zu Beginn von sich zu geben, noch irgendein Programm via RX/TX anzunehmen.

Noch ungelöstes Problem: Nur nach einem manuellen (!) Reset akzeptiert der ATMEGA328P ein neues Programm aus der Arduino-IDE via RX/TX.

Low Power Arduino ATMEGA328P

Nachdem ich den Minimal-Arduino auf dem Breadboard aufgebaut hatte, wollte ich diesen gerne über eine CR2032-Batterie mit Strom versorgen, und das möglichst lange.

Zum Glück gibt es schon einige Artikel im Internet, die sich mit dem Stromverbrauch des ATMEGA328P auseinandergesetzt haben. Allerdings erwarten hier viele einen Interrupt von Extern, was in meinem Anwendungsfall (halbwegs regelmässig einen Sensor auslesen und die Information abspeichern oder verschicken) nicht ganz praktisch war. Vor allem, weil ich den passenden Uhrenquarz nicht verfügbar habe…

Hier also (nachvollziehbar) die einzelnen Schritte, die ich bei meinem ATMEGA328P unternommen habe, um ihn den hohen Stromverbrauch streitig zu machen.

Step 1: Default blink program with 5s delay, 16 MHz ext. Osz., 3V CR2032-battery

void setup() {
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
}
 
void loop() {
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(5000);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(5000);              // wait for a second
}

Result:

  • LED On: 6.8mA
  • LED Off: 5.8mA

Step 2: All other pins as input

void setup() {
  //To reduce power, setup all pins as inputs with no pullups
  for(int x = 1 ; x < 18 ; x++){
    pinMode(x, INPUT);
    digitalWrite(x, LOW);
  }
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
}
 
void loop() {
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(5000);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(5000);              // wait for a second
}

Result:

  • LED On: 6.45mA
  • LED Off: 5.65mA

Step 3: Power Down during sleep

I’ll admit that this next step is a bit confusing, as a lot of things are introduced.

#include <avr/sleep.h> //Needed for sleep_mode
#include <avr/wdt.h>
 
volatile boolean f_wdt=1;
 
void setup() {
  //To reduce power, setup all pins as inputs with no pullups
  for(int x = 1 ; x < 18 ; x++){
    pinMode(x, INPUT);
    digitalWrite(x, LOW);
  }
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
  setup_watchdog(8);
}
 
byte state=0;
 
void loop() {
    if (f_wdt==1) {  // wait for timed out watchdog / flag is set when a watchdog timeout occurs
    f_wdt=0;       // reset flag
    switch (state){
    case 0:
      digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
      state = 1;
      setup_watchdog(0);
      break;
    case 1:
      digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
      state = 0;
      setup_watchdog(8);
      break;
    }
    system_sleep();
  }
}
 
//****************************************************************  
// set system into the sleep state 
// system wakes up when watchdog is timed out
void system_sleep() {
  // power_adc_disable()
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();
  sleep_mode();                        // System sleeps here
  sleep_disable();                     // System continues execution here when watchdog timed out 
  // power_adc_enable()
}
 
//****************************************************************
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii) {
 
  byte bb;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
 
  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCSR = bb;
  WDTCSR |= _BV(WDIE);
}
//****************************************************************  
// Watchdog Interrupt Service / is executed when  watchdog timed out
ISR(WDT_vect) {
  f_wdt=1;  // set global flag
}

Result:

  • LED On: 1.07mA
  • LED Off: 0.02mA (206uA)

As long as we depend on the internal oscillator, we won’t get any further then 206uA, as the watchdog is still enabled and drawing current. Time to get one of those nice 32kHz-oscillators.

Here are some more links related to this topic, some of those helped me in my process (some in german):

  • http://www.mikrocontroller.net/articles/Sleep_Mode
  • http://interface.khm.de/index.php/lab/interfaces-advanced/sleep_watchdog_battery/

Android App entwickeln: Erste Schritte

Abrufbare Sensoren Auflisten

Im verwendeten „Blank Activity“ ist bereits ein Textfeld enthalten, welches derzeit nur ein „Hello world!“ von sich gibt. Dieses wollen wir erstmal als Ausgabefeld für unsere ersten Tests behalten.

Zunächst möchte ich wissen, welche Sensoren in dem verwendeten Android-Gerät enthalten sind. Hierzu fügt man zunächst die folgende Prozedur in „MainActivity“ hinzu:

public void listSensors()  {
    // Find the text view
    TextView  t;
    t=(TextView)findViewById(R.id.textView);
    t.setText("");
 
    // Init SensorManager
    SensorManager sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
    // Get the list of sensors
    List listSensor = sensorManager.getSensorList(Sensor.TYPE_ALL);
    List listSensorType = new ArrayList();
    // Append all sensor names to the text view
    for(int i=0; i<listSensor.size(); i++){
        listSensorType.add(listSensor.get(i).getName());
        t.append(listSensor.get(i).getName());
        t.append("\n");
    }
}

Die IDE wird einige Begriff in ROT kennzeichnen, weil wir die notwendigen Imports nicht durchgeführt haben. Das lässt sich aber sehr bequem erledigen. Maus auf eines der roten Wörter positionieren und Alt+Eingabe drücken.

Zum Schluss beschwert sich die IDE noch darüber, dass „R.id.textView“ nicht gefunden werden kann. Dazu wechselt man in die activity_main.xml, wählt das „textView“-Element aus und vergibt in den Properties unter „id“ den Namen „textView“.

Nun müssen wir die Prozedur listSensors() nur noch im onCreate() aufrufen und schon werden beim Start der App alle Sensoren aufgelistet.

Android App entwickeln: Voraussetzungen und Installation

Schon seit langem trage ich Android-Mobiltelefone mit mir herum und nutze viele der bereitgestellten Apps in meinem täglichen Leben. Natürlich werden nicht alle meine Anforderungen durch bestehende Apps unterstützt, und eine ganz bestimmte Idee hatte ich anscheinend sogar als Erster, weshalb ich mich dazu entschloss, die entsprechende App selbst zu entwickeln. Die dabei zurückgelegten Schritte mit der entsprechend steilen Lernkurve habe ich hier dokumentiert, damit andere eine ähnliche App entwickeln können.

Schritt 1: Aktuelles JDK installieren

Die Voraussetzung für Android Studio ist ein aktuelles JDK, welches man noch BEVOR man das Android Studio installiert, installieren sollte. Da ich auf einem 64-Bit-Windows-Rechner entwickeln wollte, habe ich von der Oracle-Seite die Datei

Windows x64 jdk-XuYY-windows-x64.exe

heruntergeladen und installiert. Die Versionsnummer ändert sich laufend, daher habe ich diese hier mit XuYY umschrieben.

Schritt 2: Android Studio installieren

Das Android Studio erhält man hier: http://developer.android.com/sdk/index.html#win-bundle

Es wird bei der Installation nach dem soeben installierten Java SDK fragen, falls es dieses nicht bereits automatisch gefunden hat.

Beim ersten Starten werden weitere Dateien heruntergeladen (Android SDK Tools, Android Support Repository, Google Repository), wer also eine langsame Internetverbindung hat, kann sich getrost noch anderen Aufgaben zuwenden.

Schritt 3: Erste App erstellen

Beim Starten von Android Studio erhält man die Möglichkeit, eine leere App bereits automatisch zu erstellen. Der Einfachheit halber sollte man die mit der „Blank Activity“ auswählen, auf diese Weise hat man bereits etwas, womit man arbeiten kann.

Schritt 4: Debugger lokal starten

Man kann die neu erstellte App direkt im zum ersten Mal starten. Dabei wird im Standard ein virtuelles Device gestartet, welches die App bereits startet. Das ist zwar ganz praktisch, wenn man sein Mobiltelefon nicht noch anderweitig nutzen muss oder es nicht dabei hat. Andererseits ist es schnarchlangsam. Sinnvoll ist der lokale Test aber trotzdem, damit man weitere Fehlerquellen beim nächsten Schritt ausschließen kann.

Sollte das virtuelle Device nicht starten, oder keines zur Auswahl bereitstehen, kann man über den Android SDK Manager erst einmal alle notwendigen Dinge herunterladen lassen. Der SDK Manager liegt hier:

C:\Users\%USERNAME%\AppData\Local\Android\android-sdk

Bei mir werden direkt recht viele Dateien angezeigt, welche heruntergeladen und installiert werden sollten. Hier kann man beruhigt auf „Install xx packages“ klicken, und dann warten, bis alles heruntergeladen ist.

Schritt 5: App von Android Studio auf dem angeschlossenen Android Handy starten

Hierfür sind wiederum einige Voraussetzungen notwendig.

Das angeschlossene Mobiltelefon muss im Entwickler-Modus betrieben werden. Hierzu klickt man bei neueren Telefonen erst sieben Mal auf ein Eintrag „Build-Number“ in den Einstellungen. Daraufhin werden die „Entwickleroptionen“ verfügbar. Hier muss USB-Debugging eingeschaltet werden.

Als nächstes benötigt man einen USB-Treiber. Hierbei hilft entweder die Android-Webseite weiter, oder – wie in meinem Fall – holt sich für sein Samsung Mobiltelefon den Treiber von der samsung-Webseite. Da der Link sich immer wieder verändert, habe ich dies einfach per Google-Suche realisiert:

„Samsung Android USB Driver for Windows“

Der Google USB-Treiber ist auch über den in Schritt 4 erwähnten Android SDK Manager verfügbar, er steht ganz unten in der Liste unter „Extras“

Schritt 6: Jetzt geht es endlich ans Entwickeln

Da die Entwicklung natürlich umfangreicher ist, widme ich dieser bzw. den jeweiligen Teilaspekten einen eigenen Artikel: Android App entwickeln: Erste Schritte.

KODi on ubuntu on Intel NUC NUC5i5RYH / NUC5i5RYK

The currently new Intel NUCs are great hardware, but they need some special treatment for them to work with ubuntu und KODi. So here’s my experience and what steps I had to take to make this functional.

Hardware

  • Intel NUC5i5RYH
  • 64GB SanDisk Solid State Disk 2.5″ (6.4cm) SATA 6Gb/s MLC asynchron
  • 2 * 2GB Crucial ValueRAM DDR3-1600 SO-DIMM CL11 Single

Update BIOS

This is fairly important, make sure that you update your BIOS first. I tried to install the newest version which was available from the Intel website, but I got an error, stating that the choosen BIOS cannot be installed. So I first upgraded to the previous versions step by step, until I reached the newest BIOS. Prior to 0247, the IR receiver won’t work, so updating the BIOS is fairly necessary to get a HTPC to work.

Initial Install with Ubuntu 15.04

You won’t have any luck with Ubuntu 14.04 or 14.10, as the graphic drivers in the installer don’t work with the HD6000 from the broadwell processor. So download at least Ubuntu 15.04 as an ISO-Image and store it to your disk.

Download the Universal USB Installer, choose the previously downloaded image and create a bootable USB-Stick. Afterwards, plug it into your Intel NUC and give it power. Be sure to have a keyboard, mouse, Network and HDMI/DisplayPort-Display attached to your device. Hit „F10“ and choose the USB-stick.

Choose „Install Ubuntu“ and use all default values that are presented to you except for the login – make sure that this is automatic and that you don’t have to enter a password. Of course, you can change your username. At the end, your NUC is rebooted, be sure to remove your USB-stick.

Things to do after the first boot of 15.04

There are some lists out there in the internet, but there are two things you should consider when using the NUC as a HTPC:

  • Disable/Uninstall/Remove Amazon
  • Disable the screen saver (and the „Lock“-Feature)
  • Remove libsane (because it’s responsible for the crash if you get a „System program problem detected“ after login.

Remote Control

Ubuntu 15.04 is using rc_core, no longer lirc. Installing ir-keytable will make a new directory /etc/rc_keymaps:

sudo apt-get install ir-keytable
cd /etc/rc_keymaps

In my case, I use a Logitech Harmony One, which is configure to four devices:

  • TV (for showing the content)
  • Receiver (for Volume)
  • Intel NUC (this is ONLY needed to turn it on and off)
  • MCE (EVERY OTHER button should be mapped to this device)

It should look something like this. I guess you get the idea, even if some text is in german:

Logitech Remote

For your buttons from the remote to work, you must change some of the keys to the shortcuts from KODi. Create a new file /etc/rc_keymaps/rc-rc6-mce and put the following inside of it:

0x800f0400 KEY_0
0x800f0401 KEY_1
0x800f0402 KEY_2
0x800f0403 KEY_3
0x800f0404 KEY_4
0x800f0405 KEY_5
0x800f0406 KEY_6
0x800f0407 KEY_7
0x800f0408 KEY_8
0x800f0409 KEY_9
0x800f040a KEY_Q
0x800f040b KEY_ENTER
0x800f040c KEY_SLEEP
0x800f040d KEY_MEDIA
0x800f040e KEY_MUTE
0x800f040f KEY_I
0x800f0410 KEY_VOLUMEUP
0x800f0411 KEY_VOLUMEDOWN
0x800f0412 KEY_CHANNELUP
0x800f0413 KEY_CHANNELDOWN
0x800f0414 KEY_F
0x800f0415 KEY_R
0x800f0416 KEY_P
0x800f0417 KEY_RECORD
0x800f0418 KEY_SPACE
0x800f0419 KEY_X
0x800f041a KEY_DOT
0x800f041b KEY_COMMA
0x800f041c KEY_NUMERIC_POUND
0x800f041d KEY_NUMERIC_STAR
0x800f041e KEY_UP
0x800f041f KEY_DOWN
0x800f0420 KEY_LEFT
0x800f0421 KEY_RIGHT
0x800f0422 KEY_ENTER
0x800f0423 KEY_BACKSPACE
0x800f0424 KEY_ESC
0x800f0425 KEY_TUNER
0x800f0426 KEY_C
0x800f0427 KEY_ZOOM
0x800f0432 KEY_MODE
0x800f0433 KEY_PRESENTATION
0x800f0434 KEY_EJECTCD
0x800f043a KEY_BRIGHTNESSUP
0x800f0446 KEY_TV
0x800f0447 KEY_AUDIO
0x800f0448 KEY_PVR
0x800f0449 KEY_CAMERA
0x800f044a KEY_VIDEO
0x800f044c KEY_LANGUAGE
0x800f044d KEY_TITLE
0x800f044e KEY_PRINT
0x800f0450 KEY_RADIO
0x800f045a KEY_SUBTITLE
0x800f045b KEY_Q
0x800f045c KEY_GREEN
0x800f045d KEY_YELLOW
0x800f045e KEY_TAB
0x800f0465 KEY_POWER2
0x800f046e KEY_PLAYPAUSE
0x800f046f KEY_PLAYER
0x800f0480 KEY_BRIGHTNESSDOWN
0x800f0481 KEY_SPACE

Afterwards, load these keycodes and test them:

root@nuc:/etc/rc_keymaps# ir-keytable -w rc-rc6-mce
Wrote 63 keycode(s) to driver
root@nuc:/etc/rc_keymaps# ir-keytable -t
Testing events. Please, press CTRL-C to abort.

Install KODi

Now this step is pretty straightforward:

sudo apt-get install software-properties-common
sudo add-apt-repository ppa:team-xbmc/ppa
sudo apt-get update
sudo apt-get install kodi

Autostarting KODi after boot

We’ll make sure that KODi is started no matter which user starts the desktop. We can achieve this by adding a file to /etc/xdg/autostart:

/etc/xdg/autostart/kodi.desktop:

[Desktop Entry]
Type=Application
Name=Kodi
Exec=/opt/kodi.sh

As sometimes kodi drops to desktop (i.e. crashes), we want to make sure that it’s automatically restarted. That’s why we create another file, /opt/kodi.sh:

/opt/kodi.sh:

#!/bin/bash
killall pulseaudio
while true
do
AE_SINK=ALSA /usr/bin/kodi --standalone
done

Make sure that this file is executable:

root@nuc:/opt# chmod a+x /opt/kodi.sh

Get rid of PULSEAUDIO

Pulseaudio did not work well with my receiver, so I chose to disable it. As the default login user (NOT root), execute this command:

nuc@nuc:~$ echo "autospawn = no" > $HOME/.config/pulse/client.conf

Configure KODi

Now that we have a working KODi (simply reboot to make sure that this is true), we have to change some settings for it to work properly with the Intel NUC.

  • Language / Location / Keyboard (if necessary)
  • Audio Device (HDMI)
  • Change further settings in ~/.kodi/userdata/advancedsettings.xml (if you did this before and know what you’re doing)

Monitor ODROID C1 temperature from an external server

After a while, I got another device as a mediaplayer, called ODROID C1. This one has a much stronger cpu and has a gigabit ethernet interface. I can’t use OpenELEC on this one, as ARMv7 isn’t supported by now. So I stick with the default Ubuntu 14.04, which has its advantages, as it’s a complete Linux OS.

To monitor the temperature of this ODROID as I did before with my Raspberry Pis, I had to change the scripts a bit to get it working, my Ubuntu 14.04 uses upstart:

root@odwz:# ps -p1 | grep systemd && echo systemd || echo upstart
upstart

Of course, the prerequesite is socat:

sudo apt-get install socat

/opt/tempservice/t.sh

#!/bin/bash
cat /sys/devices/virtual/thermal/thermal_zone0/temp

/opt/tempservice/socat-service.sh

#!/bin/bash
socat -T 1 -d -d tcp-l:9888,reuseaddr,fork,crlf system:"/opt/tempservice/t.sh"

/etc/init/socat.conf

description "Socat service for temperature monitoring"
 
start on runlevel [2345]
 
stop on runlevel [016]
 
exec /opt/tempservice/socat-service.sh >>/var/log/socatservice.log 2>&1
sudo initctl reload-configuration
sudo initctl start socat

postfix: Reject some recipient adresses while using catchall on a domain

If you have a catchall on a domain – like anginf.de – you will probably get spam on some adresses which you would like to exclude from the general catchall. This can be achieved by doing some simple steps.

First you have to create a file /etc/postfix/recipient_block with all those email adresses you want rejected:

spam@anginf.de REJECT
morespam@anginf.de REJECT

To be useable for postfix, you have to postmap this file.

root@host:~# postmap /etc/postfix/recipient_block

In your /etc/postfx/main.cf, add a new line to your smtpd_recipient_restrictions:

hash:/etc/postfix/recipient_block

Now you only have to reload postfix and all mails to those mentioned in /etc/postfix/recipient_block will be rejected:

root@host:~# service postfix reload