Moteino, RFM12PiV2 & Rioja (Raspberry Pi non OpenStack)
2015-04-26
Machine-translated — the English original is authoritative.
Alla fine, ho avuto il tempo di dare il via al mio tanto atteso progetto di domotica – la mia scusa per giocare con tutto l'“Internet of Things” (IoT). Nel lungo termine vorrei coinvolgere la mia scuola locale – portando l'IoT alla comunità. Poiché il mio lavoro quotidiano richiede di smanettare con molte tecnologie divertenti, protocolli e python (hacker non programmatore) tutto nel nome dell'automazione dei datacenter (alias cloud computing per il personale marketing là fuori), sfrutterò queste competenze per creare un ecosistema di domotica robusto. I DL360 e gli iLO saranno sostituiti da Raspberry Pi e Arduino.
Ci sono molti ottimi blog in rete che mi hanno ispirato, come JeeLabs , LowPowerLabs e l'angolo di Martin sul web. Questi ragazzi sono degli esperti! Si prega di consultare questi siti se si desidera costruire il proprio sistema. Io sto costruendo per il gusto di imparare, esistono già fantastiche soluzioni pronte all'uso. Questo blog si limiterà a presentare le scoperte che penso possano interessare gli altri mentre intraprendo questo viaggio…
Giocare con le comunicazioni RF a basso consumo
Se vi state chiedendo perché non mi limito al WiFi per le comunicazioni, la risposta è semplicemente alimentazione e portata! I moduli WiFi sono ghiotti di energia rispetto ai dispositivi RF più semplici. Non tutti i dispositivi collegati a Internet saranno vicini a una fonte di alimentazione, quindi sarà necessario farli funzionare a batteria – ad esempio, monitor delle piante, sensori di temperatura remoti, ecc. Alla fine, questi dispositivi a batteria invieranno le loro informazioni a Internet attraverso un gateway Raspberry Pi (RPi). L'RPi avrà sia connettività Internet che connettività RF.
La prima sfida che ho affrontato è stata valutare alcuni dispositivi RF pronti e a basso costo, che includevano un paio di Moteino (che sono superbi), di Felix di LowPowerLabs.com e il RFM12PiV2 del progetto OpenEnergyMonitor. Questo dispositivo si collega al Raspberry Pi e sarà il gateway verso Internet per tutti i miei dispositivi IoT basati su RF.
Avendo scelto dispositivi RF da due progetti diversi, hanno bisogno di alcune modifiche per comunicare correttamente tra loro, ed è di questo che tratterà il resto di questo blog.
Ciò che questi dispositivi hanno in comune è che utilizzano entrambi la piattaforma di sviluppo compatibile con Arduino basata sul chip ATMega328. Di conseguenza, entrambi possono essere programmati utilizzando l'IDE di Arduino. I dispositivi hanno anche una scheda figlia integrata che contiene il trasceiver HopeRF RFM12B.
La differenza sta nel fatto che eseguono programmi diversi (conosciuti anche come sketch nel mondo Arduino) e i loro orologi hardware sono stati progettati in modo leggermente diverso. Il Moteino utilizza un segnale di clock esterno da 16 MHz, mentre il RFM12PiV2 utilizza il clock interno da 8 MHz integrato nell'ATMega328. Quest'ultima informazione è vitale quando si sincronizza la trasmissione tra i dispositivi.
Ho deciso di utilizzare gli sketch di test dei Moteino trovati qui – Node e Gateway, modificando solo l'indirizzamento e il baud rate come si può vedere di seguito:
Sketch Node
// 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);
}
Sketch Gateway
// 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;
}
Scaricare lo sketch sul Moteino
Questo è semplice: basta collegare il Moteino direttamente a un PC che esegue l'IDE di Arduino e utilizzare il processo standard di Arduino. Questi dispositivi hanno anche una molto utile capacità di programmazione wireless, che viene trattata qui.
Scaricare lo sketch sul RFM12PiV2 (usando il Raspberry Pi)
Questo processo è un po' più complicato. Dobbiamo prima compilare lo sketch del gateway utilizzando l'IDE di Arduino e poi individuare il file bin compilato.
Abilitare l'output verboso nelle preferenze dell'IDE di Arduino come mostrato di seguito:

Ora, quando si compila lo sketch, la finestra di output fornirà la posizione del file compilato che dovrai trasferire sul Raspberry Pi.

Assicurati che la porta seriale sul Raspberry Pi sia stata abilitata come dettagliato qui.
L'ultimo pezzo di questo puzzle – come caricare nuovo codice dal Raspberry Pi al RFM12PiV2 – è già stato documentato qui ma sarà anche delineato di nuovo di seguito:
$ 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>
Infine, usa il tuo strumento preferito per leggere la porta seriale sul Raspberry Pi – ho optato per screen. Nel lungo termine userò uno script python.
NOTA Ricorda la differenza nelle velocità di clock – questo entra in gioco ora. Nonostante gli sketch impostino entrambi il baud rate a 115200, quando ci si connette al RFM12PiV2 che funziona a metà della velocità di clock, 8MHz invece di 16MHz, è necessario impostare il baud rate a 57600 e NON 115200.
Ora dovresti vedere qualcosa del genere

Mettendo tutto insieme avrai un sistema di comunicazione di base funzionante da Moteino a RFM12PiV2.

Taaaa – Daaaa!
Purtroppo, apparentemente il modulo RFM12B è ora fuori produzione, quindi dovrò rifare tutto questo con il RFM69 o forse proverò questi
🙂
Originally published on allthingscloud.eu (2015-04-26).



