From ac2ba83a3613c07543e2cb29128ebe2d6d4ee522 Mon Sep 17 00:00:00 2001 From: Martin Harizanov Date: Wed, 29 Aug 2012 16:07:47 +0300 Subject: [PATCH] PERL EmonBase example --- .../TinySensor_Current_monitor.ino | 4 + .../TinySensor_InternalTemperatureSensor.ino | 54 +++++-- .../TinySensor_PinChangeInterrupt.ino | 140 ++++++++++++++++++ perl_gateway/serial.pl | 120 +++++++++++++++ 4 files changed, 307 insertions(+), 11 deletions(-) create mode 100644 TinySensor_PinChangeInterrupt/TinySensor_PinChangeInterrupt.ino create mode 100644 perl_gateway/serial.pl diff --git a/TinySensor_Current_monitor/TinySensor_Current_monitor.ino b/TinySensor_Current_monitor/TinySensor_Current_monitor.ino index e2833ec..a6f350a 100644 --- a/TinySensor_Current_monitor/TinySensor_Current_monitor.ino +++ b/TinySensor_Current_monitor/TinySensor_Current_monitor.ino @@ -95,6 +95,10 @@ void setup() { void loop() { + #define BODS 7 //BOD Sleep bit in MCUCR + #define BODSE 2 //BOD Sleep enable bit in MCUCR + MCUCR |= _BV(BODS) | _BV(BODSE); //turn off the brown-out detector + setPrescaler(3); // div 8, i.e. 1 MHz bitClear(PRR, PRADC); // power up the ADC ADCSRA |= bit(ADEN); // enable the ADC diff --git a/TinySensor_InternalTemperatureSensor/TinySensor_InternalTemperatureSensor.ino b/TinySensor_InternalTemperatureSensor/TinySensor_InternalTemperatureSensor.ino index eb2ce3d..0eb2526 100644 --- a/TinySensor_InternalTemperatureSensor/TinySensor_InternalTemperatureSensor.ino +++ b/TinySensor_InternalTemperatureSensor/TinySensor_InternalTemperatureSensor.ino @@ -4,17 +4,23 @@ // GNU GPL V3 //-------------------------------------------------------------------------------------- +#ifdef F_CPU +#undef F_CPU +#endif +#define F_CPU 1000000 // 1 MHz + #include // https://github.com/jcw/jeelib #include "pins_arduino.h" ISR(WDT_vect) { Sleepy::watchdogEvent(); } // interrupt handler for JeeLabs Sleepy power saving -#define myNodeID 17 // RF12 node ID in the range 1-30 +#define myNodeID 18 // RF12 node ID in the range 1-30 #define network 210 // RF12 Network group #define freq RF12_868MHZ // Frequency of RFM12B module +#define LEDpin PB0 -#define TEMPERATURE_ADJUSTMENT 2 +#define TEMPERATURE_ADJUSTMENT 26-43 #define EXTREMES_RATIO 5 #define MAXINT 32767 #define MININT -32767 @@ -32,47 +38,73 @@ int pos=0; typedef struct { int temp; // Temperature reading int supplyV; // Supply voltage - int temp2; // Temperature reading } Payload; Payload temptx; +static void setPrescaler (uint8_t mode) { + cli(); + CLKPR = bit(CLKPCE); + CLKPR = mode; + sei(); +} void setup() { + + setPrescaler(1); // div 1, i.e. 4 MHz + pinMode(LEDpin,OUTPUT); + digitalWrite(LEDpin,LOW); + delay(1000); + digitalWrite(LEDpin,HIGH); + rf12_initialize(myNodeID,freq,network); // Initialize RFM12 with settings defined above // Adjust low battery voltage to 2.2V UNTESTED!!!!!!!!!!!!!!!!!!!!! rf12_control(0xC040); rf12_sleep(0); // Put the RFM12 to sleep - Serial.begin(9600); +// Serial.begin(9600); + PRR = bit(PRTIM1); // only keep timer 0 going } void loop() { + pinMode(LEDpin,OUTPUT); + digitalWrite(LEDpin,LOW); + setPrescaler(3); // div 8, i.e. 1 MHz + bitClear(PRR, PRADC); // power up the ADC + ADCSRA |= bit(ADEN); // enable the ADC + Sleepy::loseSomeTime(16); // Allow 10ms for the sensor to be ready + int_sensor_init(); - sprint(); +// sprint(); temptx.temp = in_c() * 100; // Convert temperature to an integer, reversed at receiving end - temptx.temp2 = 1 * 100; // Convert temperature to an integer, reversed at receiving end - temptx.supplyV = readVcc(); // Get supply voltage + ADCSRA &= ~ bit(ADEN); // disable the ADC + bitSet(PRR, PRADC); // power down the ADC + + digitalWrite(LEDpin,HIGH); + rfwrite(); // Send data via RF for(int j = 0; j < 1; j++) { // Sleep for 5 minutes - Sleepy::loseSomeTime(1000); //JeeLabs power save function: enter low power mode for 60 seconds (valid range 16-65000 ms) + Sleepy::loseSomeTime(60000); //JeeLabs power save function: enter low power mode for 60 seconds (valid range 16-65000 ms) } } //-------------------------------------------------------------------------------------------------- // Send payload data via RF //-------------------------------------------------------------------------------------------------- - static void rfwrite(){ +static void rfwrite(){ + setPrescaler(1); // div 1, i.e. 4 MHz + bitClear(PRR, PRUSI); // enable USI h/w rf12_sleep(-1); //wake up RF module while (!rf12_canSend()) - rf12_recvDone(); + rf12_recvDone(); rf12_sendStart(0, &temptx, sizeof temptx); rf12_sendWait(2); //wait for RF to finish sending while in standby mode rf12_sleep(0); //put RF module to sleep + bitSet(PRR, PRUSI); // disable USI h/w + setPrescaler(4); // div 4, i.e. 1 MHz } - //-------------------------------------------------------------------------------------------------- // Read current supply voltage //-------------------------------------------------------------------------------------------------- diff --git a/TinySensor_PinChangeInterrupt/TinySensor_PinChangeInterrupt.ino b/TinySensor_PinChangeInterrupt/TinySensor_PinChangeInterrupt.ino new file mode 100644 index 0000000..0574287 --- /dev/null +++ b/TinySensor_PinChangeInterrupt/TinySensor_PinChangeInterrupt.ino @@ -0,0 +1,140 @@ +//-------------------------------------------------------------------------------------- +// Internal temperature measurement of Attiny84 based TinySensor +// harizanov.com +// GNU GPL V3 +//-------------------------------------------------------------------------------------- + +#ifdef F_CPU +#undef F_CPU +#endif +#define F_CPU 1000000 // 1 MHz + +#include + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +#include // https://github.com/jcw/jeelib +#include "pins_arduino.h" + +ISR(WDT_vect) { Sleepy::watchdogEvent(); } // interrupt handler for JeeLabs Sleepy power saving + +#define myNodeID 8 // RF12 node ID in the range 1-30 +#define network 210 // RF12 Network group +#define freq RF12_868MHZ // Frequency of RFM12B module + +#define LEDpin PB0 + + +//######################################################################################################################## +//Data Structure to be sent +//######################################################################################################################## + + typedef struct { + int state; // State + int supplyV; // Supply voltage + } Payload; + +static Payload temptx; + +static void setPrescaler (uint8_t mode) { + cli(); + CLKPR = bit(CLKPCE); + CLKPR = mode; + sei(); +} + + ISR(PCINT0_vect) { + temptx.state=bitRead(PINA,1); + } + +void setup() { + + setPrescaler(1); // div 1, i.e. 4 MHz + pinMode(LEDpin,OUTPUT); + digitalWrite(LEDpin,LOW); + delay(1000); + digitalWrite(LEDpin,HIGH); + + + pinMode(1,INPUT); + sbi(GIMSK,PCIE0); // Turn on Pin Change interrupt + sbi(PCMSK0,PCINT1); // Which pins are affected by the interrupt + + rf12_initialize(myNodeID,freq,network); // Initialize RFM12 with settings defined above + // Adjust low battery voltage to 2.2V + rf12_control(0xC040); + rf12_sleep(0); // Put the RFM12 to sleep +// Serial.begin(9600); + PRR = bit(PRTIM1); // only keep timer 0 going +} + +void loop() { + pinMode(LEDpin,OUTPUT); + digitalWrite(LEDpin,LOW); + setPrescaler(3); // div 8, i.e. 1 MHz + bitClear(PRR, PRADC); // power up the ADC + ADCSRA |= bit(ADEN); // enable the ADC + Sleepy::loseSomeTime(16); // Allow 10ms for the sensor to be ready + +// temptx.state=1; + temptx.supplyV = readVcc(); // Get supply voltage + + ADCSRA &= ~ bit(ADEN); // disable the ADC + bitSet(PRR, PRADC); // power down the ADC + + digitalWrite(LEDpin,HIGH); + + rfwrite(); // Send data via RF + + /* + for(int j = 0; j < 1; j++) { // Sleep for 5 minutes + Sleepy::loseSomeTime(60000); //JeeLabs power save function: enter low power mode for 60 seconds (valid range 16-65000 ms) + } + */ + + + set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode + sleep_mode(); // System sleeps here + +} + +//-------------------------------------------------------------------------------------------------- +// Send payload data via RF +//-------------------------------------------------------------------------------------------------- +static void rfwrite(){ + setPrescaler(1); // div 1, i.e. 4 MHz + bitClear(PRR, PRUSI); // enable USI h/w + rf12_sleep(-1); //wake up RF module + while (!rf12_canSend()) + rf12_recvDone(); + rf12_sendStart(0, &temptx, sizeof temptx); + rf12_sendWait(2); //wait for RF to finish sending while in standby mode + rf12_sleep(0); //put RF module to sleep + bitSet(PRR, PRUSI); // disable USI h/w + setPrescaler(4); // div 4, i.e. 1 MHz +} +//-------------------------------------------------------------------------------------------------- +// Read current supply voltage +//-------------------------------------------------------------------------------------------------- + + long readVcc() { + long result; + // Read 1.1V reference against Vcc + ADMUX = _BV(MUX5) | _BV(MUX0); + delay(2); // Wait for Vref to settle + ADCSRA |= _BV(ADSC); // Convert + while (bit_is_set(ADCSRA,ADSC)); + result = ADCL; + result |= ADCH<<8; + result = 1126400L / result; // Back-calculate Vcc in mV + return result; +} + + + + diff --git a/perl_gateway/serial.pl b/perl_gateway/serial.pl new file mode 100644 index 0000000..9e2fc57 --- /dev/null +++ b/perl_gateway/serial.pl @@ -0,0 +1,120 @@ +#!/usr/bin/perl -w +# Reads data from serial port and posts to emoncms + + +# Run apt-get install libdevice-serialport-perl +# if you ger "Can't locate device/SerialPort.pm in @INC (@INC includes ..." + + +# use lib '/usr/lib/perl5/Device' +# sudo apt-get install libwww-mechanize-perl + +# Martin Harizanov +# http://harizanov.com + + +# Declare the subroutines +sub trim($); + + +BEGIN { + push @INC,"/usr/lib/perl5/"; + } + +use strict; +use Device::SerialPort qw( :PARAM :STAT 0.07 ); +use WWW::Mechanize; +use Time::localtime; +use Scalar::Util 'looks_like_number'; + +print "Serial to EmonCMS gateway for RaspberryPi with TinySensor\r\n"; + +my $PORT = "/dev/ttyAMA0"; + +my $ob = Device::SerialPort->new($PORT); +$ob->baudrate(9600); +$ob->parity("none"); +$ob->databits(8); +$ob->stopbits(1); +$ob->handshake("xoff"); +$ob->write_settings; + +$ob->lookclear; + +$ob->write("\r\n"); +$ob->write("22i"); #Node ID=22 +sleep 2; +$ob->write("8b"); #868Mhz +sleep 2; +$ob->write("210g"); #Group=210 +sleep 2; +$ob->lookclear; + +open(SERIAL, "+>$PORT"); + +while (my $line = trim()) { + print $line; print "\r\n"; + my @values = split(' ', $line); + my $bindata; + if(looks_like_number($values[0]) && $values[0] >=1 && $values[0]<=26) { + + $bindata=""; + for(my $j=1; $j<@values; $j++) { + $bindata.=sprintf ("%.2x",$values[$j]); + } + #print $bindata . "\r\n"; + $bindata=pack("H*",$bindata); + + #Example of decoding packet content for nodes 17 and 18 + if($values[0]==18 || $values[0]==17) { + + my($temperature, $battery) = unpack("ss",$bindata); + $temperature /=100; + print "Temperature $temperature\n"; + print "Battery $battery\n"; + + } + + my $msubs =""; + for(my $i=1; $i<@values; $i+=2){ + $msubs .= $values[$i] + $values[$i+1]*256; + if($i) {$msubs .= ","}; + } + post2emoncms($values[0],$msubs); + + my $hour=localtime->hour(); + my $min=localtime->min(); + $ob->write("$hour,00,$min,00,s\r\n"); + } +} + +sub post2emoncms { + +my $ua = WWW::Mechanize->new(); +my $url = "http://127.0.0.1/emoncms3/api/post?apikey=23338d373027ce83b1f81b9e9563b629&node=" . $_[0] ."&csv=" . $_[1]; +#print $url; print "\r\n"; +my $response = $ua->get($url); +if ($response->is_success) +{ +#print "Success!\n"; +#my $c = $ua->content; +#print ("$c"); +} +else +{ +#print "Failed to update emoncms!"; +#die $response->status_line; +} + +} + + +# Perl trim function to remove whitespace from the start and end of the string +sub trim($) +{ + my $string = shift; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} +#