Codesnippet: php / Raspberry Pi => Fritzbox => Telefonanruf

Jaaaa, ich hab‘ endlich auch einen Raspberry Pi und bin total begeistert – obwohl ich nach wie vor keine Ahnung habe was ich damit jetzt konkret anstellen soll 🙂
Beim rumspielen ist jetzt ein Snippet entstanden, das sich per telnet an der Fritzbox anmeldet und per AT-Befehl kurz eine Nummer anruft.

!#/usr/bin/php5
<?php

$fritzIP  = '192.168.178.1';
$pass     = 'xxxxxxxxxx';
$number   = '0173xxxxxx';
$sleep    = 10;


if ($fp = fsockopen($fritzIP, 23)) {
  $buffer = '';
  while (!feof($fp) && !preg_match('/password/', $buffer)) {
    $buffer .= fread($fp, 1);
  }
  
  fputs($fp, $pass . "rn");
  sleep(1);
  fputs($fp, 'echo "ATDT' . $number . '" | nc 127.0.0.1 1011' . "rn");
  sleep($sleep);
  fputs($fp, 'echo "ATH" | nc 127.0.0.1 1011' . "rn");
  sleep(1);
  
  
} else {
  echo 'Telnet connection failed ' . $fritzIP;
}
Werbeanzeigen

RFM01 (RFM12) auf’s Breadboard

Dieses äußerst beliebte Funkmodul hat tragischerweise ein Rastermaß von 2mm und passt daher nicht auf ein Standardbreadboard mit 2.54mm. Auf eine Lochrasterplatine legen und verkabeln ist nichts für Grobmotoriker (boah, was hab‘ ich geflucht), deshalb hier mein – wie ich finde – eigentlich ganz guter Lösungsweg:

Beinchen von geopferten Widerständen ranlöten, in die Lochrasterplatine stecken und ganz konventionell festlöten.

Fail! Dummerweise ist das jetzt eine Spalte breiter als mein Breadboard und passt daher immer noch nicht rein. Hab‘ echt die Lust dran verloren, aber der Lösungsansatz war an sich schon ganz gut, oder? 🙂

ISP lohnt sich

Mein neustes Spielzeug ist ein AVR ISP und nach den ersten Versuchen kann ich nur begeistert sagen: die Anschaffung lohnt sich auch für normale Aruino User!

Hintergrundwissen:
Normalerweise programmiert man einen nackten Atmel Mikrocontroller – wie er sich auf jedem Arduino befindet – über die SPI Schnittstelle mit Hilfe eines In-System Programmers. Das man einen Arduino im Normalfall dagegen über die serielle Schnittstelle programmiert liegt daran, dass auf dem Mikrocontroller bereits ein Bootloader installiert ist, der nach einem Reset erstmal kurz schaut ob da erst ein neues Programm über die serielle Schnittstelle hochgeladen werden soll. Ich habe lange darüber nachgegrübelt, wieso die nicht gleich einen ISP mit auf das Board gepackt haben und vermute es liegt daran, dass man die serielle Schnittstelle zum Computer beim Prototyping ohnehin fast immer benötigt und das ganze mit dieser Methode anfängerfreundlicher und kostengünstiger ist.

Wozu ein ISP beim Arduino?
Da ein Arduino ohne Bootloader nicht über die serielle Schnittstelle programmiert werden kann, braucht man einen ISP zwingend um zunächst einmalig den Bootloader zu installieren (bei fertigen gekauften Arduinos ist der bereits vorinstalliert).
Man kann den ISP aber auch dazu verwenden, einen Sketch direkt hochzuladen. Das hat folgende Vorteile:

  • Der Bootloader fällt weg, man spart also Speicherplatz auf dem Controller
  • Der Upload geht spürbar schneller (Getestet mit einem Atmega8 auf einem Duemilanove Board mit Diamex ISP – ca. 3 Sekunden statt ca. 9 Sekunden)
  • Die serielle Schnittstelle bleibt frei, man kann sich also das lästige Serial Monitor öffnen/schließen Spielchen bei jedem Upload sparen

Konfiguration ISP
Wenn der eigene ISP nicht in der Liste unter „Tools->Burn Bootloader“ auftaucht, muss man den zunächst einmal in der Datei /arduino-0022/hardware/programmers.txt anlegen. Bei mir habe ich folgenden Eintrag oben hinzugefügt:

diamexisp.name=Diamex ISP
diamexisp.communication=serial
diamexisp.protocol=stk500v2
diamexisp.speed=19200

Wenn man die Arduino IDE anschließend neu startet, findet man den neuen ISP auch wie folgt im Menü:

Konfiguration Board
In der Datei /arduino-022/hardware/boards.txt muss man angeben, bei welchen Boards der Upload von Sketchen über den ISP laufen soll. Das geht mit der Konfigurationsvariable [board].upload.using=[programmer]. Am besten kopiert man dazu einen bestehenden Eintrag, entfernt die [board].bootloader Einträge, fügt die [board].upload.using Angabe hinzu und gibt dem ganzen einen neuen Namen. Wie zum Beispiel hier aus meiner Config:

atmega8isp.name=ATmega8 & ISP
atmega8isp.upload.protocol=stk500v2
atmega8isp.upload.maximum_size=30720
atmega8isp.upload.speed=57600
atmega8isp.upload.using=diamexisp
atmega8isp.build.mcu=atmega8
atmega8isp.build.f_cpu=16000000L
atmega8isp.build.core=arduino

Alternative zum Serial Monitor
Jetzt können wir Sketche über den Com Port des ISP hochladen und serielle Daten über den Com Port des Arduino USB Anschlusses verarbeiten. Dummerweise gibt es in der Arduino IDE nur einen Com Port für beide Zwecke zur Auswahl. Wenn man den eingebauten Serial Monitor verwendet, müsste man also vor und nach jedem Upload den Port ändern, was ziemlich lästig wäre. Die Rettung ist ein alternatives Terminalprogramm wie zum Beispiel dieses hier. Einfach die Arduino IDE auf den Com Port des ISP stellen und im alternativen Terminalprogramm auf den USB Anschluss.

Use any Arduino pin for transmission with the IRremote libary by soft PWM

I really love Ken Shiriffs IRremote libary for Arduino but it had a dealbreaking limitation for my current project: it makes use of the PWM functionality and is therefore bound to pin 3. As I really needed all PWM pins for other stuff and didn’t want to upgrade to a Mega board, I worked out this hack.

A IR signal consists of on- and off states and that is literally switching the IR LED on and off in special periods. While a off state is actually switching the LED off at all, a on state is more like blinking with a really high frequency of 38kHz. This is a typical task for PWM but after all it is again nothing else than just switching it on and off.

First at all we have to find out how fast we have to switch on/off with this frequency.

36000 / 1s = 1 / n * s
n = 1/36000s =  27,7 μs

So we have to switch it on and off every 27,7μs (fortunately the delayMicroseconds function works accurately for values above 3μs) and it’s simple as this:

while (OnStateDuration) {
  digitalWrite( sendPin, HIGH);
  delayMicroseconds(14);
  digitalWrite( sendPin, LOW);
  delayMicroseconds(14);
}

=== Instruction ===
You can download the modified libary here or go through these steps:

Replace the following methods in IRremote.cpp:

void IRsend::mark(int time) {
  unsigned long n = micros();
  while (micros()-n < time) {
    digitalWrite(irparams.sendpin, HIGH);
    delayMicroseconds(irparams.pulselength);
    digitalWrite(irparams.sendpin, LOW);
    delayMicroseconds(irparams.pulselength);
  }
}

void IRsend::space(int time) {
  digitalWrite(irparams.sendpin, LOW);
  delayMicroseconds(time);
}

void IRsend::enableIROut(unsigned int khz) {
  irparams.pulselength = 500 / khz;
  pinMode(irparams.sendpin, OUTPUT);
  digitalWrite(irparams.sendpin, LOW); // When not sending PWM, we want it low
}

IRrecv::IRrecv(int recvpin)
{
  irparams.recvpin = recvpin;
  irparams.blinkflag = 0;
}

Add the sendpin parameter to the constructor signature in IRremote.h:

class IRsend
{
public:
  IRsend(int sendpin);

Define the sendpin and period variables in IRremoteInt.h:

typedef struct {
  uint8_t sendpin;
  unsigned int pulselength;


When using in a sketch, you have to specify the pin for transmission:

IRsend irsend;  // deprecated
IRsend irsend(10);  // send on pin 10


Flattr this

======

PS: If you’re experimenting with IR you might find this useful. You can use an ordinary red LED instead of a IR LED on short a short distance of let’s say about 2 or 3 cm. I accident found this and I’m very happy about not needing to use my mobile phones camera to check the IR light any more.

Oszilloskop für Arme

Ja, ich bin immer noch bei meinen Fernbedienungen.

Die grundsätzliche Funktionsweise war ja folgende: das Signal besteht aus An/Aus-Zuständen in einer bestimmten zeitlichen Abfolge. Das kann man wunderbar in einem Koordinatensystem (X-Achse Zeit, Y-Achse Zustand) visualisieren – nichts anderes macht ja auch ein Oszilloskop oder Logic Analyzer. Da normalsterbliche Bastler wie ich sowas aber nicht besitzen (Hallo Familie, das ist ein Wink mit dem Weihnachtszaunpfahl), habe ich dafür ein php-Script geschrieben.

Die RCSwitch Libary misst die Zeitabstände zwischen den An- und Aus-Zuständen und speichert diese in einem Array. Das Array wird an die Callback Methode übergeben und kann dort ausgegeben werden.

Arduino Sketch:

#include 

RCSwitch mySwitch = RCSwitch(3);

void setup() {
  Serial.begin(9600);
  mySwitch.enableReceive(0, output);
}

void loop() {

}

void output(unsigned long decimal, unsigned int length, unsigned int delay, unsigned int* raw) {
    for (int i=0; i< length*2; i++) {
      Serial.print(raw[i]);
      Serial.print(",");
    }
}

Im Serial Monitor bekomme ich nach Drücken einer Fernbedienung also eine kommaseparierte Liste mit Mikrosekunden die ein An-/Aus-Zustand jeweils dauert. Copy&Paste unter: http://test.sui.li/oszi.php und schwupps hat man das ganze hübsch aufbereitet 🙂

Hier ein paar Beispiele:

Signal eines Pollin Steckdosensets:


Signal eines Pollin Funkdimmers:


Signal zum öffnen des Kofferraumes einer billigen Nachrüst-Zentralverriegelung für’s Auto:


Signale zum aufschließen meines MG mit der Original Lucas 17TN Fernbedienung (Rolling Code, der ändert sich jedes mal):


Flattr this

Funkfernbedienungen: neue Erkentnisse und decodieren

Kennst du eine, kennst du alle. Wie ich inzwischen festgestellt habe, basieren die meisten billigen Funkfernbedienungen auf dem gleichen Protokoll. Neben den bei Funksteckdosen beliebten SC2262, HX2262, PT2262 wären da noch die EV1527, RT1527, FP1527, HS1527 (alle untereinander kompatibel, gefunden in den Funkdimmern von Pollin oder erschreckenderweise auch in der Fernbedienung für die Zentralverriegelung meines Autos… ich glaube zu dem Thema werde ich nochmal einen eigenen Artikel schreiben) zu erwähnen.

Die 2262er senden vom Nutzer konfigurierte 8 oder 10Bit lange Adressen gefolgt von 4 oder 2Bit langen Befehlen und einem Sync-Bit. Die 1527er senden einen Sync-Bit, eine fest im Chip verdratete, „einmalige“ 20Bit Adresse und einen 4Bit langen Befehl. Da man die Three-State Bits „1“, „0“, „F“ bei den 2262ern auch zu je zwei Two-State Bits „1“, „0“ substituieren kann (1=11, 0=00, F=01), senden also eigentlich beide letzendlich immer nur einen 24Bit Wert und eine Pause an deren Länge man das Timing ermitteln kann.

Hier ist mein erstes zusammengehacktes Arduino Sketch zum decodieren aller 433MHz Fernbedienungen die nach diesem Prinzip funktionieren (433MHz AM Empfänger oder falls nicht zur Hand einfach den im vorletzten Blogeintrag beschriebenen Dout der Fernbedienung an Pin#2):

#define maxChanges 500

unsigned int duration;
unsigned int changeCount;
unsigned int timings[maxChanges];
unsigned long lastTime;
unsigned int repeatCount;

void setup() {
  Serial.begin(9600);
  
  lastTime = micros();
  repeatCount = 0;
  changeCount = 0;
  
  attachInterrupt(0, r, CHANGE); 
}

void loop() {

}

void output() {
  unsigned long code = 0;
  unsigned long delay = timings[1] / 31;
  unsigned long delayTolerance = delay*0.2;
  Serial.print("Delay: ");
  Serial.println(delay);
  for (int i = 2; i+1<changeCount ; i=i+2) {
    if (timings[i] > delay-delayTolerance && timings[i] < delay+delayTolerance && timings[i+1] > delay*3-delayTolerance && timings[i+1] < delay*3+delayTolerance) {
      Serial.print("0");
      code = code << 1;
    } else if (timings[i] > delay*3-delayTolerance && timings[i] < delay*+delayTolerance && timings[i+1] > delay-delayTolerance && timings[i+1] < delay+delayTolerance) {
      Serial.print("1");
      code+=1;
      code = code << 1;
    } else {
      Serial.println("");
      Serial.print("Failed: ");
      Serial.print(i);
      Serial.print("/");
      Serial.print(timings[i]);
      Serial.print("/");
      Serial.println(timings[i+1]);
    }
  }
  code = code >> 1;
  Serial.println();
  Serial.print("Code: ");
  Serial.println(code);
    Serial.println();
}

void r() {
  long time = micros();
  duration = time - lastTime;
  
  if (duration > 5000 && duration > timings[1] - 200 && duration < timings[1] + 200) {
    repeatCount++;
    if (repeatCount == 2) {
      output();
      repeatCount = 0;
    }
    changeCount = 0;
  } else if (duration > 6000) {
    changeCount = 0;
  }
  
  if (changeCount >= maxChanges) {
    changeCount = 0;
    repeatCount = 0;
  } else {
    changeCount++;
  }
  timings[changeCount] = duration;
  lastTime = time;
}

Update: Eine Empfangs- und Decodierfuntion findet sich inzwischen auch in der RCSwitch Libary


Flattr this