Blog previously known as 'Home Theatre PC'
Comments have been disabled due to spam and lack of time for moderation.
Use the contact link on top to get in touch if you wish.

1-wire temperatures with Arduino

  07/27/11 18:47, by Esa, Categories: Hardware, Software

I have used 1-wire temperature sensors (DS18S20) around my house for a few years now. Just recently the home made serial port adapter stopped working and I thought I'd look into replacing it with Arduino.

There was already 1-wire library and dallas temperature library available for Arduino under GPL license and wiring only required connecting data line to any of the digital io ports (I chose port 2) and 4k7 resistor between Arduino 5V and 1-wire bus data line for parasite power and grounding of course. Here's the code which reads the sensors and outputs to the usbserial.

#include <OneWire.h>
#include "DallasTemperature.h"

#define ONE_WIRE_BUS_DATA_PORT 3
#define LOOP_DELAY_1 30000 // max 32k...
#define LOOP_DELAY_2 30000
#define _NUM_SAMPLES 3
#define _SAMPLE_DELAY 1000

OneWire oneWire(ONE_WIRE_BUS_DATA_PORT);
DallasTemperature sensors(&oneWire);

void setup(void)
{
  Serial.begin(9600);
}

char* batoh(uint8_t deviceAddress[]) {
  char* buf_str = (char*) malloc(2*8 + 1);
  char* buf_ptr = buf_str;
  for (uint8_t i = 0; i < 8; i++) {
    buf_ptr += sprintf(buf_ptr, "%02X", deviceAddress[i]);
  }
  *(buf_ptr) = '\0';
  return buf_str;
}

float getTemp(uint8_t* addr, int samples, int delay_ms) {
  float sample[samples];
  float tmp;
  uint8_t l,i,j;
  for ( l = 0; l < samples; l++) {
    sensors.requestTemperaturesByAddress(addr); 
    sample[l] = sensors.getTempC(addr); 
    Serial.print("D "); 
    Serial.print(batoh(addr)); Serial.print(" "); 
    Serial.print(sample[l]); 
    Serial.println(" D");
    delay(delay_ms);
  }
  
  for ( i = 0; i < samples; i++ ) {
    for ( j = 1; j < (samples-i); j++ ) {
      if (sample[j-1] > sample[j]) {
        tmp = sample[j-1];
        sample[j-1]=sample[j];
        sample[j]=tmp;
      }
    }
  }
 
    
  return sample[samples/2];
}

void loop(void)
{ 
  uint8_t i;
  uint8_t addr[8];  
  uint8_t dcnt;
  
  sensors.begin();

  dcnt = sensors.getDeviceCount();
  //sensors.requestTemperatures();
  
  for ( i = 0; i < dcnt; i++ ) {
    sensors.getAddress(addr,i);
    float temp_c = getTemp(addr,_NUM_SAMPLES,_SAMPLE_DELAY);
    if (temp_c < -55.0 || temp_c > 125.0) { // range really -55 - +125, retry once if value returned is outside that range
      delay(_SAMPLE_DELAY);
      sensors.begin();
      temp_c = getTemp(addr,_NUM_SAMPLES,_SAMPLE_DELAY);
    } 
      Serial.print(batoh(addr));
      Serial.print(" ");
      Serial.println(temp_c);
  } 
  
  delay(LOOP_DELAY_1);
  delay(LOOP_DELAY_2);
}

Why read the same sensor several times? Because some of my sensors want to send either 85.00 or -127.00 every now and then once or twice in a row. Also sometimes I've been getting reading of the previous requested sensor when reading the next one. Reading 3 times and discarding the highest & lowest is not optimal, but it's good enough for me, for now. I had these same problems with the old, now broken, system using digitemp.

All the readings go to mysql database from which I create graphs with jpgraph library. I didn't want to include any date & time logic in the arduino part, so I'm reading the values from the serial port and inserting them to the db with 'current_timestamp'. I do that by reading the serial port constantly, with awk

awk '{ gsub("\\r",""); if (NF == 2) print "insert into temps (time_date,temp_c,sensor_serial) values (current_timestamp,\047"$2"\047,\047"$1"\047);"; fflush();}' /dev/cu.usbserial-A9007TRT | /opt/local/bin/mysql5 -u temps -pxxxxxx automation2

I use OSX for that, so I've made a little launchd script out of it (in linux the same can be done with inittab), it just makes sure the process keeps running.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Disabled</key>
    <false/>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>com.cue.onewire.temperatures</string>
    <key>RunAtLoad</key>
    <true/>
    <key>Umask</key>
    <integer>7</integer>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/local/bin/storetemperatures.sh</string>
    </array>    
    <key>UserName</key>
    <string>esav</string>
</dict>
</plist>

Tell launchd to load your plist and you're done. Note that I've put the awk into a shell script because I didn't want to escape those parameters to plist &amp;#58;&amp;#41;

sudo launchctl load /Library/LaunchDaemons/your.own.plist

Ubuntu 10.04 Lucid Lynx - PXE bootable installation without any bootable media to begin with

  09/21/10 23:22, by Esa, Categories: Software

I have an old Thinkpad, which cannot boot from anything else than over the network using PXE client. I do have server in the lan that can handle PXE clients.

A quick summary how to get Lucid Lynx to be served over NFS, using installation CD and USB stick to install it to. Or like me, using PXE booting installation CD (there are instructions on the net on how to do it, if you have problems, ask here).

  • Boot the machine with the installation cd and do whatever kind of installation you want to the USB stick, make it one partition with no swap.
  • When finished, reboot the machine with the installation CD again, mount the USB stick, mount proc & dev to it and then chroot

Assuming your USB stick goes to sda1

sudo mkdir -p /mnt/stick
sudo mount /dev/sda1 /mnt/stick
sudo mount -t proc none /mnt/stick/proc
sudo mount -o bind /dev /mnt/stick/dev
sudo chroot /mnt/stick
source /etc/profile

You're now basically using your brand new Lucid Lynx on a stick. Next you need to generate initrd image which contains necessary modules etc for your pxe boot.

  • Create a copy of /etc/initramfs-tools
  • Edit /etc/initramfs-tools-pxe/initramfs.conf. Change line 'MODULES=most' to 'MODULES=netboot' and line 'BOOT=local' to 'BOOT=nfs'
  • Generate new initrd.
  • Edit fstab, remove existing root definition, add new usig /dev/nfs
  • Transfer the USB stick contents to PXE server
cp -R /etc/initramfs-tools /etc/initramfs-tools-pxe
nano /etc/initramfs-tools-pxe/initramfs.conf
mkinitramfs -d /etc/initramfs-tools-pxe -o /boot/initrd.img-2.6.32-21-generic-pxe 2.6.32-21-generic
nano /etc/fstab

Contents of /etc/fstab after editing

# /etc/fstab: static file system information.
#
# Use 'blkid -o value -s UUID' to print the universally unique identifier
# for a device; this may be used with UUID= as a more robust way to name
# devices that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
/dev/nfs	/		nfs	defaults	1	1
proc            /proc           proc    nodev,noexec,nosuid 0       0

To transfer the filesystem contents to PXE server you can use whatever method you want, just preserver file permissions. I used rsync over ssh.

rsync -avz --exclude /proc -e ssh / root@10.10.10.1:/tftproot/stick/

Now you're done on the client side. Next copy boot/initrd.img-2.6.32-21-generic-pxe and boot/vmlinuz-2.6.32-21-generic to the root of your tftp server. Then configure the rest PXE server (use google, or ask here). Remember to add the directory with the stick contents to /etc/exports. This is my /tftproot/pxelinux.cfg/01-XX-XX-XX-XX-XX-XX (x's being the mac address of the thinkpad)

timeout 10
prompt 1
default Ubuntu

label Ubuntu
        kernel vmlinuz-2.6.32-21-generic
        append root=/dev/nfs initrd=initrd.img-2.6.32-21-generic-pxe nfsroot=10.10.10.100:/tftproot/stick ip=dhcp rw nosplash 

Reboot the client and you're done.

Samba (smb,cifs) share from Mac OSX Snow Leopard to Linux

  09/08/10 20:15, by Esa, Categories: Software

If you are trying to mount a directory from OSX with 'Windows sharing' enabled and you have problems with characters not showing properly then your linux system has something else than utf8 in nls_default.

To make it work, simply put something like


//10.10.10.10/music /mnt/music cifs rw,credentials=/etc/credentials,iocharset=utf8 0 0

into your /etc/fstab (the important bit being iocharset=utf8). To avoid having to type plaintext passwords in world readable file (/etc/fstab) you can specify credentials file, which can be readable by only root. Credentials file needs to have two lines in it

username=zzzz
password=yyyy

All you need to do now is

umount /mnt/music & mount /mnt/music

iTunes fails to connect to iTunes Store

  09/02/10 16:57, by Esa, Categories: Software

Apple actually introduced a bug in iTunes 9.1, and it still isn't fixed in iTunes 10.

Under normal circumstances the bug doesn't matter, but it does if you use dansguardian, possibly others as well. At first I tried to figure out what is wrong with my squid (transparent proxy) but in the end the problem turned out to be dansguardian (well, itunes, but I can't fix that).

Apple has somewhere in their code additional 'dot' in url they are requesting http://ax.init.itunes.apple.com./ dansguardian throws malformed url error for url's like that. The fix is really simple, but still requires you to patch the source and recompile.

The fix is to just chop the damn thing off before dansguardian does whatever it does with it. I haven't noticed anything breaking because of this &amp;#58;&amp;#41;

--- dansguardian-2.10.0.3/src/HTTPHeader.cpp	2010-09-02 16:49:18.000000000 +0300
+++ dansguardian-2.10.0.3-fixed/src/HTTPHeader.cpp	2010-09-02 16:48:00.000000000 +0300
@@ -941,6 +941,10 @@ String HTTPHeader::url()
 				}
 				hostname.removeWhiteSpace();  // remove rubbish like
 				// ^M and blanks
+                		if (hostname.endsWith(".")) {
+                  			hostname.chop();
+                		}
+
 				hostname = "http://" + hostname;
 				answer = hostname + answer;
 			}

 

There's the patch, if you're not familiar with patch, you can just find the location in that file (HTTPHeader.cpp) and add the lines marked with '+' and the do the regular ./configure && make && make install magic.

Subsonic 4.0.1 web interface over https

  08/13/10 18:52, by Esa, Categories: Software

It works. Kind of.

If you try to get to https://yourhost:44300/ you get redirected to http://yourhost:44300/login.view;jsessionid=bla, just change the protocol of that url to https and you'll get login screen. When you login, it once again redirects you to wrong place, this time http://yourhost:44300/, once again change the protocol to https and you should end up in https://yourhost:44300/index.view

Once you get there, it works, the player and all, over https.

Streaming doesn't work with lighttpd mod_proxy, with stunnel it does

  08/12/10 17:52, by Esa, Categories: Software

I turned out that lighttpd mod_proxy wants to get the whole response before it starts sending it back to client. A bug has been reported in their trac about it a long time ago.

I don't want to wait for ffmpeg to finish transcoding before the music starts streaming to my phone, so I tried stunnel.

kippo ~ # emerge -av stunnel

If you get errors emerging stunnel about groupadd switch -r not existing, you need to update sys-apps/shadow

kippo ~ # emerge -av shadow

Add your tunnel to /etc/stunnel/stunnel.conf

[subsonic]
accept	= 44300
connect = 10.10.10.10:4040

Start the daemon

kippo ~ # /etc/init.d/stunnel start

Open iSub and now the streaming starts right away. Yay.

Subsonic media streamer to iPhone over HTTPS

  08/09/10 19:14, by Esa, Categories: Software

I came across a wonderful media streamer, thanks to a colleague. I use mpd (music player daemon) to play music around the house, but I was really missing a way to stream it all to my phone.

Subsonic supports streaming with on the fly transcoding using lame & ffmepg. Installing it is pretty straightforward. I installed Subsonic to my Mac Mini, which sits behind my gateway (linux box).

Subsonic on OSX is just like any installer you see, just click next, next & next and you're done. Open the browser to localhost:4040 and change the password / create users / set up music directories.

You also need to install lame & ffmpeg for the transcoding to work. Subsonic on OSX assumes you use MacPorts for those, or at least it assumes the binaries are in /opt/local/bin. If you don't want macports, you can get the binaries however you want and put them in /Library/Application Support/Subsonic/transcode/.

mini:~ esav$ ls -l /Library/Application\ Support/Subsonic/transcode/
total 16
lrwxr-xr-x   1 root  admin   21 Aug  9 13:40 ffmpeg -> /opt/local/bin/ffmpeg
lrwxr-xr-x   1 root  admin   19 Aug  9 13:40 lame -> /opt/local/bin/lame

To install ffmepg & lame just download MacPorts and do

mini:~ esav$ sudo port selfupdate
mini:~ esav$ sudo port install lame
mini:~ esav$ sudo port install ffmpeg

Getting HTTPS requires some additional work. And unfortunately it won't work with the web ui, but it does work with the REST API subsonic provides. Web UI has some issues with redirecting. For example the login page forces the page to http:// instead of https://.

I have the router/gateway machine running linux & lighttpd so my setup goes like this:

Create a self-signed cert for next 10 years &amp;#58;&amp;#41;

kippo ~ # openssl req -new -x509 -keyout /etc/lighttpd/server.pem -out /etc/lighttpd/server.pem -days 3650 -nodes

Configure lighttpd, create a new 'server' which listens to a port you choose, and set it up to proxy the traffic to your subsonic server.

$SERVER["socket"] == ":44300" {
 ssl.engine  = "enable" 
 ssl.pemfile = "/etc/lighttpd/server.pem" 
 proxy.server  = ( "" => ( 
                  ( "host" => "10.10.10.10", "port" => 4040 )
                 ) ) 
}

You also need to enable mod_proxy

server.modules = (
.
.
.
    "mod_proxy",
.
.
.
)

And open the port in the firewall, for example:

iptables -I INPUT 10 -p tcp --dport 44300 -j ACCEPT

Of course change the index from 10 to whatever you need. Usually appending to INPUT chain is a bad idea as the rules are processed top down, and usually you already have something to block traffic as last rule on your chain (like moving traffic to a different chain for logging & dropping etc).

Next, set your iSub Media Streamer to https://yourhost:44300/ and you're done.

I got error about user being null on the first attempt, but that fixed itself when I just deleted the server from iSub and created it again.

[2010-08-10 13:48:14,260] INFO RESTRequestParameterProcessingFilter - Authentication failed for user null

<< Previous :: Next >>

Search

Contents

powered by b2evolution