Moteino, RFM12PiV2 & Rioja (Raspberry Pi nicht OpenStack)
2015-04-26
Machine-translated — the English original is authoritative.
Also, endlich hatte ich die Zeit, mein lang ersehntes Heimautomatisierungsprojekt zu starten – meine Ausrede, um mit dem ganzen „Internet of Things“ (IoT) zu spielen. Langfristig möchte ich meine lokale Schule einbeziehen – IoT in die Gemeinschaft bringen. Da mein Beruf das Herumspielen mit vielen lustigen Technologien, Protokollen und Python erfordert (Hacker, nicht Programmierer), alles im Namen der Rechenzentrumsautomatisierung (auch bekannt als Cloud Computing für die Marketing-Leute da draußen), werde ich diese Fähigkeiten nutzen, um ein robustes Heimautomatisierungs-Ökosystem zu schaffen. DL360s und iLOs werden durch Raspberry Pis und Arduinos ersetzt.
Es gibt viele großartige Blogs im Internet, die mich inspiriert haben, wie JeeLabs , LowPowerLabs und Martin’s corner on the web. Diese Leute sind die Experten! Bitte konsultieren Sie diese Websites, wenn Sie Ihr eigenes System bauen möchten. Ich baue aus Lernzwecken, fantastische fertige Systeme existieren bereits jetzt. Dieser Blog wird lediglich die Entdeckungen präsentieren, von denen ich denke, dass sie andere interessieren könnten, während ich auf meiner Reise bin…
Experimentieren mit stromsparenden RF-Kommunikationen
Wenn Sie sich fragen, warum ich nicht einfach bei WiFi für die Kommunikation bleibe, lautet die Antwort einfach Stromverbrauch und Reichweite! WiFi-Module sind im Vergleich zu einfacheren RF-Geräten stromhungrig. Nicht alle Geräte, die mit dem Internet verbunden werden sollen, werden in der Nähe einer Stromquelle sein, daher wird es notwendig sein, diese mit Batterien zu betreiben – z. B. Pflanzenmonitore, entfernte Temperatursensoren usw. Letztendlich werden diese batteriebetriebenen Geräte ihre Informationen über ein Gateway-Raspberry-Pi (RPi) ins Internet senden. Das RPi wird sowohl Internet- als auch RF-Konnektivität haben.
Die erste Herausforderung, der ich mich stellen musste, war die Bewertung einiger kostengünstiger, fertiger RF-Geräte, darunter ein paar Moteinos (die sind super), von Felix bei LowPowerLabs.com und der RFM12PiV2 vom OpenEnergyMonitor-Projekt. Dieses Gerät wird in den Raspberry Pi gesteckt und wird das Gateway zum Internet für all meine RF-basierten IoT-Geräte sein.
Da ich RF-Geräte von zwei verschiedenen Projekten ausgewählt habe, müssen sie etwas angepasst werden, damit sie korrekt miteinander kommunizieren können, und genau darum geht es im Rest dieses Blogs.
Was diese Geräte gemeinsam haben, ist, dass sie beide die Arduino-kompatible Entwicklungsplattform basierend auf dem ATMega328-Chip verwenden. Als Ergebnis können beide mit der Arduino IDE programmiert werden. Die Geräte haben auch eine integrierte Tochterplatine, die den HopeRF RFM12B-Transceiver enthält.
Sie unterscheiden sich darin, dass sie verschiedene Programme (auch Sketche in der Arduino-Welt genannt) ausführen und ihre Hardware-Taktgeber auch etwas unterschiedlich architektonisch gestaltet sind. Der Moteino verwendet ein externes 16-MHz-Takt Signal, während der RFM12PiV2 den internen 8-MHz-Takt verwendet, der in den ATMega328 eingebaut ist. Diese letzte Information ist entscheidend, wenn die Übertragung zwischen den Geräten synchronisiert wird.
Ich entschied mich, die Moteino-Test-Sketche zu verwenden, die sich hier befinden – Node und Gateway, wobei nur die Adressierung und die Baudrate geändert wurden, wie als Nächstes zu sehen ist:
Node Sketch
// Test sketch that is loaded on slave Moteinos
// It will send an encrypted message to the master/gateway every TRANSMITPERIOD
// It will respond to any ACKed messages from the master
// Every 3rd message will also be ACKed (request ACK from master).
#include <RFM12B.h>
#include <SPIFlash.h>
#include <SPI.h>b
#include <avr/sleep.h>
#define MYID 123 // node ID used for this unit
#define NETWORKID 50
#define GATEWAYID 1
#define FREQUENCY RF12_433MHZ //Match this with the version of your Moteino! (others: RF12_433MHZ, RF12_915MHZ)
#define KEY "ABCDABCDABCDABCD"
int TRANSMITPERIOD = 500; //transmit a packet to gateway so often (in ms)
#define SERIAL_BAUD 115200
#define ACK_TIME 50 // # of ms to wait for an ack
char input = 0;
RFM12B radio;
SPIFlash flash(8, 0xEF30); //EF30 for Windbond 4mbit flash
boolean requestACK = false;
byte sendSize=0;
char payload[] = "123 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
void setup()
{
Serial.begin(SERIAL_BAUD);
radio.Initialize(MYID, FREQUENCY, NETWORKID, 0);
radio.Encrypt((byte*)KEY);
char buff[50];
sprintf(buff, "Transmitting at %d Mhz...", FREQUENCY == RF12_433MHZ ? 433 : FREQUENCY== RF12_868MHZ ? 868 : 915);
Serial.println(buff);
if (flash.initialize())
Serial.println("SPI Flash Init OK!");
else
Serial.println("SPI Flash Init FAIL! (is chip present?)");
}
long lastPeriod = -1;
void loop()
{
//process any serial input
if (Serial.available() > 0) {
input = Serial.read();
if (input >= 48 && input <= 57) //[0,9]
{
TRANSMITPERIOD = 100 * (input-48);
if (TRANSMITPERIOD == 0) TRANSMITPERIOD = 1000;
Serial.print("\nChanging delay to ");
Serial.print(TRANSMITPERIOD);
Serial.println("ms\n");
}
else if (input == 'd') //d=dump flash area
{
Serial.println("Flash content:");
int counter = 0;
while(counter<=256){
Serial.print(flash.readByte(counter++), HEX);
Serial.print('.');
}
while(flash.busy());
Serial.println();
}
else if (input == 'e')
{
Serial.print("Erasing Flash chip ... ");
flash.chipErase();
while(flash.busy());
Serial.println("DONE");
}
else if (input == 'i')
{
Serial.print("DeviceID: ");
Serial.println(flash.readDeviceId(), HEX);
}
}
//check for any received packets
if (radio.ReceiveComplete())
{
if (radio.CRCPass())
{
Serial.print('[');Serial.print(radio.GetSender(), DEC);Serial.print("] ");
for (byte i = 0; i < *radio.DataLen; i++)
Serial.print((char)radio.Data[i]);
if (radio.ACKRequested())
{
radio.SendACK();
Serial.print(" - ACK sent.");
}
Blink(9,5);
}
}
int currPeriod = millis()/TRANSMITPERIOD;
if (currPeriod != lastPeriod)
{
lastPeriod=currPeriod;
//Send data periodically to GATEWAY
Serial.print("Sending[");
Serial.print(sendSize);
Serial.print("]: ");
for(byte i = 0; i < sendSize; i++)
Serial.print((char)payload[i]);
requestACK = ((sendSize % 3) == 0); //request ACK every 3rd xmission
radio.Send(GATEWAYID, payload, sendSize, requestACK);
if (requestACK)
{
Serial.print(" - waiting for ACK...");
if (waitForAck(GATEWAYID)) Serial.print("ok!");
else Serial.print("nothing...");
}
sendSize = (sendSize + 1) % 31;
Serial.println();
Blink(9,5);
}
//else { Serial.print("currPeriod = "); Serial.print(currPeriod); Serial.print(" lastPeriod = "); Serial.println(lastPeriod); }
}
// wait a few milliseconds for proper ACK to me, return true if indeed received
static bool waitForAck(byte theNodeID) {
long now = millis();
while (millis() - now <= ACK_TIME) {
if (radio.ACKReceived(theNodeID))
return true;
}
return false;
}
void Blink(byte PIN, int DELAY_MS)
{
pinMode(PIN, OUTPUT);
digitalWrite(PIN,HIGH);
delay(DELAY_MS);
digitalWrite(PIN,LOW);
}
Gateway Sketch
// Test sketch that is loaded on master Moteinos
// It will listen for any packets received from slave Moteinos
// If an ACK request message is received, it sends and ACK and also
// sends an ACKed message to the slave, ensuring that 2-way
// communication is functional on the slave Moteino
#include <RFM12B.h>
#define SERIAL_BAUD 115200
#define NODEID 1 // network ID used for this unit
#define NETWORKID 50
#define FREQUENCY RF12_433MHZ //Match this with the version of your Moteino! (others: RF12_433MHZ, RF12_915MHZ)
#define KEY "ABCDABCDABCDABCD" //encryption key
#define ACK_TIME 50 // # of ms to wait for an ack
uint8_t input[RF12_MAXDATA];
RFM12B radio;
void setup()
{
pinMode(9, OUTPUT);
radio.Initialize(NODEID, FREQUENCY, NETWORKID);
radio.Encrypt((byte*)KEY);
Serial.begin(SERIAL_BAUD);
char buff[50];
sprintf(buff, "Listening at %d Mhz...", FREQUENCY == RF12_433MHZ ? 433 : FREQUENCY== RF12_868MHZ ? 868 : 915);
Serial.println(buff);
}
byte recvCount = 0;
void loop()
{
if (radio.ReceiveComplete())
{
if (radio.CRCPass())
{
digitalWrite(9,1);
Serial.print('[');Serial.print(radio.GetSender(), DEC);Serial.print("] ");
for (byte i = 0; i < *radio.DataLen; i++)
Serial.print((char)radio.Data[i]);
if (radio.ACKRequested())
{
byte theNodeID = radio.GetSender();
radio.SendACK();
//when a node requests an ACK, respond to the ACK and also send a packet requesting an ACK
//This way both TX/RX NODE functions are tested on 1 end at the GATEWAY
Serial.print(" - ACK sent. Sending packet to node ");
Serial.print(theNodeID);
delay(10);
radio.Send(theNodeID, "ACK TEST", 8, true);
Serial.print(" - waiting for ACK...");
if (waitForAck(theNodeID)) Serial.print("ok!");
else Serial.print("nothing...");
}
delay(5);
digitalWrite(9,0);
}
else Serial.print("BAD-CRC");
Serial.println();
}
}
// wait a few milliseconds for proper ACK to me, return true if indeed received
static bool waitForAck(byte theNodeID) {
long now = millis();
while (millis() - now <= ACK_TIME) {
if (radio.ACKReceived(theNodeID))
return true;
}
return false;
}
Herunterladen des Sketches auf den Moteino
Dies ist einfach, indem man den Moteino direkt an einen PC anschließt, auf dem die Arduino IDE läuft, und den Standard-Arduino-Prozess verwendet. Diese Geräte haben auch eine sehr nützliche drahtlose Programmierfunktion, die hier beschrieben wird.
Herunterladen des Sketches auf den RFM12PiV2 (unter Verwendung des Raspberry Pi)
Dieser Prozess ist etwas kniffliger. Wir müssen den Gateway-Sketch zuerst mit der Arduino IDE kompilieren und dann die kompilierte Binärdatei finden.
Aktivieren Sie die ausführliche Ausgabe in den Einstellungen der Arduino IDE, wie unten gezeigt:

Wenn Sie den Sketch jetzt kompilieren, gibt das Ausgabefenster den Speicherort der kompilierten Datei an, die Sie auf den Raspberry Pi übertragen müssen.

Stellen Sie sicher, dass der serielle Port am Raspberry Pi aktiviert wurde, wie hier detailliert beschrieben.
Das letzte Stück dieses Puzzles – wie man neuen Code vom Raspberry Pi auf den RFM12PiV2 hochlädt – wurde bereits hier dokumentiert, wird aber auch unten noch einmal umrissen:
$ sudo apt-get update
$ sudo apt-get install -y arduino python-dev python-rpi.gpio
$ git clone https://github.com/mharizanov/avrdude-rpi.git
$ cd avrdude-rpi
$ sudo cp autoreset /usr/bin
$ sudo cp avrdude-autoreset /usr/bin
$ sudo mv /usr/bin/avrdude /usr/bin/avrdude-original
$ sudo ln -s /usr/bin/avrdude-autoreset /usr/bin/avrdude
# Change to the directory where the binary file has been copied
$ avrdude -v -c arduino -p ATMEGA328P -P /dev/ttyAMA0 -b 38400 -U flash:w:<Enter Filename Here and remove arrow brackets>
Schließlich verwenden Sie Ihr bevorzugtes Tool, um den seriellen Port am Raspberry Pi auszulesen – ich habe mich für screen entschieden. Langfristig werde ich ein Python-Skript verwenden.
HINWEIS Denken Sie an den Unterschied in den Taktraten – das spielt jetzt eine Rolle. Trotz der Tatsache, dass beide Sketche die Baudrate auf 115200 einstellen, ist es beim Verbinden mit dem RFM12PiV2, der mit der halben Taktrate läuft, 8 MHz statt 16 MHz, notwendig, die Baudrate auf 57600 und NICHT 115200 einzustellen.
Jetzt sollten Sie so etwas sehen

Alles zusammengefügt ergibt ein funktionierendes Moteino-zu-RFM12PiV2-Basiskommunikationssystem.

Taaaa – Daaaa!
Leider ist das RFM12B-Modul anscheinend nicht mehr lieferbar, also muss ich das alles mit dem RFM69 wiederholen oder vielleicht versuche ich diese
🙂
Originally published on allthingscloud.eu (2015-04-26).



