Kategorie-Archiv: Raspberry Pi

Raspberry Pi

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

Monitor temperature and humidity with DHT11 sensor on raspberry pi

The DHT11 sensor includes a temperature and a humidity sensor. I connected it with my raspberry pi and transmit the data to an external cacti server, which polls the data regularly from the raspberry pi.

Step 1: Wire the sensor

While facing the open side of the sensor (NOT the one with the sticker on it), connect the pins as following

  • Leftmost pin = V+ — connect with 3V3 (Pin 1) from raspberry pi
  • Second pin = DATA — connect with GPIO4 (Pin 7) from raspberry pi AND via a 4.7k-10k resistor with 3V3
  • Third pin = Do NOT connect
  • Rightmost pin = GND — connect with GND (Pin 6) from raspberry pi
Raspberry PI Rev2 GPIO pinout
Raspberry PI Rev2 GPIO pinout

Step 2: Get the BCM2835 library and compile / install

The latest version can always be found here: http://www.airspayce.com/mikem/bcm2835/
As the time of writing, this was 1.36

cd
mkdir -p work/bcm2835
cd work/bcm2835
wget http://www.open.com.au/mikem/bcm2835/bcm2835-1.36.tar.gz
tar xvfz bcm2835-1.36.tar.gz
cd ./bcm2835-1.36
./configure
make
sudo make install

Step 3: Get the Adafruit python code

sudo apt-get update
sudo apt-get -y install git
git clone https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code
cd ./Adafruit-Raspberry-Pi-Python-Code
cd ./Adafruit_DHT_Driver
make

After successfully compiling the Adafruit Driver, you can check if your sensor is already working. Keep in mind that the DHT11 is SLOW and won’t react if asked more than once within 2 or 3 seconds. If you don’t get any result after the first query, wait a few seconds (at least 3) and try again. If the problem persists, your wiring might be wrong.

sudo ./Adafruit_DHT 11 4

Step 4: Modify Adafruit python code

The original Adafruit code is giving too much information for simple cacti input parameters. A modification of the source code is necessary. Along with changing the output, I also removed all references to DHT22 and AM2302 to make the file a bit smaller:

ada_sm.c

//  How to access GPIO registers from C-code on the Raspberry-Pi
//  Example program
//  15-January-2012
//  Dom and Gert
// Access from ARM Running Linux
#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <bcm2835.h>
#include <unistd.h>
#define MAXTIMINGS 100
 
#define DHT11 11
 
int readDHT(int type, int pin);
 
int main(int argc, char **argv)
{
  if (!bcm2835_init())
        return 1;
 
  if (argc != 3) {
        printf("usage: %s [11] GPIOpin#\n", argv[0]);
        printf("example: %s 11 4 - Read from an DHT11 connected to GPIO #4\n", argv[0]);
        return 2;
  }
  int type = 0;
  if (strcmp(argv[1], "11") == 0) type = DHT11;
  if (type == 0) {
        printf("Select 11 as type!\n");
        return 3;
  }
  int dhtpin = atoi(argv[2]);
  if (dhtpin <= 0) {
        printf("Please select a valid GPIO pin #\n");
        return 3;
  }
  readDHT(type, dhtpin);
  return 0;
} // main
 
int bits[250], data[100];
int bitidx = 0;
 
int readDHT(int type, int pin) {
  int counter = 0;
  int laststate = HIGH;
  int j=0;
 
  // Set GPIO pin to output
  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
 
  bcm2835_gpio_write(pin, HIGH);
  usleep(500000);  // 500 ms
  bcm2835_gpio_write(pin, LOW);
  usleep(20000);
 
  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);
 
  data[0] = data[1] = data[2] = data[3] = data[4] = 0;
 
  // wait for pin to drop?
  while (bcm2835_gpio_lev(pin) == 1) {
    usleep(1);
  }
 
  // read data!
  for (int i=0; i< MAXTIMINGS; i++) {
    counter = 0;
    while ( bcm2835_gpio_lev(pin) == laststate) {
        counter++;
        //nanosleep(1);         // overclocking might change this?
        if (counter == 1000)
          break;
    }
    laststate = bcm2835_gpio_lev(pin);
    if (counter == 1000) break;
    bits[bitidx++] = counter;
 
    if ((i>3) && (i%2 == 0)) {
      // shove each bit into the storage bytes
      data[j/8] <<= 1;
      if (counter > 200)
        data[j/8] |= 1;
      j++;
    }
  }
 
  if ((j >= 39) &&
      (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
     if (type == DHT11)
        printf("temp:%d hum:%d\n", data[2], data[0]);
    return 1;
  }
 
  return 0;
}

Compile the file with this command line (if you saved the above .c-file as „ada_sm.c“)

gcc ada_sm.c -l bcm2835 -std=gnu99 -o ada_sm

The output should be compatible with cacti:

$ sudo ./ada_sm 11 4
temp:23 hum:33

Step 5: Add a socat service

I’ve explained how to achieve this in another post, you only need a new shell script which will make sure that the readouts were given:

/usr/local/bin/dht11.sh

#!/bin/bash
result=""
while [ -z "${result}" ];
do
result=$(sudo /home/pi/work/dht11/ada_sm 11 4)
sleep 3
done
echo ${result}

Here the contents the configuration file for socat:

/etc/default/socat

OPTIONS="-T 30 -t 30 tcp-l:9889,reuseaddr,fork,crlf system:\"/usr/local/bin/dht11.sh\""

Step 6: Read data from the socat service on the cacti host

This is explained in another post as well, but the needed script in the site/scripts-directory is a bit different, here’s what I used. Keep in mind that you have to change „PI-IP“ to your local DNS or IP-Adress of the Raspberry Pi.

/usr/share/cacti/site/scripts/dht11.sh

#!/bin/bash
outstring=$(/bin/nc PI-IP 9889  | tr -d '\r')
echo "${outstring}"

Resources on the internet

These links helped me set this up:
http://www.messtechniklabor.de/artikel-h0000-temperatur_und_luftfeuchtigkeit_messen.html
https://learn.adafruit.com/dht-humidity-sensing-on-raspberry-pi-with-gdocs-logging/wiring
http://www.airspayce.com/mikem/bcm2835/

Monitor Raspberry Pi temperature from an external server

I’m using a raspberry pi with XBMC as a mediaplayer. As I didn’t want to have a lot of trouble maintaining it, I decided to try OpenELEC. It works fine, but it’s really limited to only the media-related parts.

I wanted to know how much the temperature changes when using my raspberry pi and I already had a working cacti-server in my LAN. But what would be the best way to read the temperature from the pi without pushing too many binaries onto the system?

The answer is „socat“ – and of course, the binary is NOT part of the OpenELEC-distribution. But I was able to compile the socat as a static binary on another raspberry pi, which was runnning raspbian.

./configure LDFLAGS="-static"
make

Copy the resulting binary socat to the OpenELEC-raspberry. If you can’t create the binary yourself, you can download it from here:

socat 1.7.2.4 statically linked

socat: ELF 32-bit LSB  executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.26, BuildID[sha1]=8ca6f5b38a7836cefe0721295d946dd9f90fb98e, not stripped

Put the socat in a new directory called /storage/tempservice/.

Add the following two files in the same directory /storage/tempservice/:

socat-service.sh

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

t.sh

#!/bin/bash
cat /sys/class/thermal/thermal_zone0/temp

socat-service.sh will later start the service, while t.sh reads the temperature itself.

To make sure that the service is started on startup, we introduce a new system service in system.d: Change to the directory /storage/.config/system.d and add the following file:

socat.service

[Unit]
Description=SocatTempServer
 
[Service]
Type=simple
ExecStart=/storage/tempservice/socat-service.sh
 
[Install]
WantedBy=multi-user.target

And enable the service:

systemctl enable socat.service

Reboot and test from the other system in the LAN whether we can read the temperature:

nc PI-IP 9888 | tr -d '\r'

Now all you have to do is include the result in a cacti script and show the result. 🙂

Here’s what it may look like:

An example for a cacti picture measuring raspberyy pi temperatures
An example for a cacti picture measuring raspberry pi temperatures

Raspberry Pi on LG 42LH9000 with OpenELEC and IR Remote


UPDATE: Newest kernels require you to add the GPIO-Information directly into the config.txt, otherwise the LIRC won’t be available:

Append this to your /boot/config.txt (if you attach the IR receiver to GPIO 23 as stated in the article below):

dtoverlay=lirc-rpi,gpio_in_pin=23

I attached a Raspberry PI (Model B) via HDMI to my LG 42LH9000, a 42″ LED-TV from 2009. With the newest version of OpenELEC 4.0.0, I was suprised to find out that the most commands via CEC work out nicely. The only trouble I had was, that the „Back“ and „Exit“-Buttons didn’t work at all. Instead, I had to press „STOP“ and „OK“ directly after each other in a short time for „Back“ and „STOP“ and „PAUSE“ for an „Exit“.

As I was using an IR remote control anyways, I thought the raspberry could receive the data for the two missing buttons directly. At first, I needed and IR receiver diode. That was easy, as I still had an old, broken mini-helicopter which was steered using IR. As the helicopter itself was useless, I desoldered the IR receiver. I couldn’t make out a model number, so I simply guessed.

Facing the side with the receiver (that’s the side with the little bump), you can see three legs coming out of it. The left one I used for „DATA“, the middle one for „GND“ and the right one for „Vs“. As the helicopter was working with a lithium battery, I simply guessed that the receiver will work out nicely with only 3.3V.

Next step was wiring the receiver to the Raspberry PI. I needed +3.3V, GND and a useful GPIO-pin. Searching the web, I found this great view of the GPIOs. I’m sorry that I can’t give any credit to the one who created this graphic, as there are no copyright notices anywhere to find.

Raspberry PI Rev2 GPIO pinout
Raspberry PI Rev2 GPIO pinout

I attached the left („DATA“)-leg to GPIO 23, the middle leg to GND and the right leg („Vs“) to +3.3V.

After logging into my Raspberry PI, which was already running OpenELEC, I tried these commands to test if the IR receiver was working:

modprobe lirc_rpi gpio_in_pin=23 debug=1
dmesg

The dmesg should return something like this:

[118254.914704] lirc_dev: IR Remote Control driver registered, major 248
[118254.915686] lirc_rpi: module is from the staging directory, the quality is unknown, you have been warned.
[118254.939532] lirc_rpi: is_right_chip bcm2708_gpio 0
[118254.939904] lirc_rpi: to_irq 193
[118255.831302] lirc_rpi: auto-detected active low receiver on GPIO pin 23
[118255.831921] lirc_rpi lirc_rpi.0: lirc_dev: driver lirc_rpi registered at minor = 0
[118255.831946] lirc_rpi: driver registered!

Now we want to make sure that the receiver is actually working. Grap your remote control, run this command and see if anything happens on the console.

mode2 -d /dev/lirc0

This is my example output when I hit the „BACK“-Button on my remote control:

space 2189447
pulse 9022
space 4473
pulse 571
space 611
pulse 520
space 567
pulse 584
space 1658
pulse 588
space 541
pulse 588
space 552
pulse 590
space 542
pulse 587
space 541
pulse 568
space 571
pulse 585
space 1659
pulse 586
space 1696
pulse 544
space 547
pulse 562

The IR receiver actually works and we just saw the RAW input from the sensor!

To make sure that the next time the Raspberry PI is started, that the module is loaded correctly, type in this command:

echo "options lirc_rpi gpio_in_pin=23" >/storage/.config/modprobe.d/lirc_rpi.conf

Make sure that no LIRCD is running:

killall lircd

And start recording the input from the two buttons:

mkdir -p ~/work/lirc
cd ~/work/lirc
irrecord -d /dev/lirc0 inputlg

The last command guides you through a wizard, the two buttons are called BTN_BACK and KEY_EXIT. I added the RED button as well and mapped it to KEY_C, as this is the context menu for the KODI.

As a result, you should have a file inputlg with these contents:

# Please make this file available to others
# by sending it to <lirc@bartelmus.de>
#
# this config file was automatically generated
# using lirc-0.9.1-git(default) on Sun May 11 22:47:19 2014
#
# contributed by
#
# brand:                       inputlg.conf
# model no. of remote control:
# devices being controlled by this remote:
#
 
begin remote
 
  name  inputlg.conf
  bits           16
  flags SPACE_ENC|CONST_LENGTH
  eps            30
  aeps          100
 
  header       9006  4492
  one           565  1677
  zero          565   566
  ptrail        562
  repeat       9008  2246
  pre_data_bits   16
  pre_data       0x20DF
  gap          108236
  toggle_bit_mask 0x0
 
      begin codes
          KEY_EXIT                 0x14EB
          KEY_MENU                 0xDA25
          KEY_C                    0x4EB1
      end codes
 
end remote

As you can see I really only added the two buttons that I still needed. If you want to add any more buttons, you must know the correct names for them. These can be retrieved with a simple command. As there are MANY possible buttons available, I limit the output to those which might be useful for me. The following command for example shows me the „EXIT“-Button:

irrecord --list-namespace | grep -i exit

I assigend my „BACK“-Button from the remote to „KEY_EXIT“, as this works like a „back-button“ within KODI. The „EXIT“-Button from my remote is used as a „MENU“ key.

If you want to know which buttons are used by KODI (and in what manner), the answers lie inside the file /usr/share/kodi/system/Lircmap.xml with the section

Now copy the file to the correct location:

cp inputlg /storage/.config/lircd.conf

And reboot:

sync
reboot

If you want to add other keys, which are normally not part of the remote control, here are the steps to work it our correctly:

Make sure that you have the Lircmap.xml from the system in your storage:

cp /usr/share/kodi/system/Lircmap.xml /storage/.kodi/userdata/Lircmap.xml

And add in the last section which starts with <remote device="devinput"> the following information:

<title>KEY_C</title>

Here are the links that helped me set this up:
http://wiki.openelec.tv/index.php?title=Guide_To_lirc_rpi_GPIO_Receiver
http://wiki.openelec.tv/index.php?title=Guide_To_Test_a_Remote_and_Remap_Keys