OK I didn't do anything about the power reduction using an arduino,
nRF24L01 and the DHT22, but I did have working code to have my DHT22 in wireless mode.
I design the python code to be able to set more modules and it is quite fast.
I made it works like the master/slave system
The Raspberry Pi loops on each sensor and will ask the sensor to give it's data. Like I said I'm using the shockburst method. The RaspberryPi send to a specific sensor the current time and the next times the sensor should send the next data. The Arduino on the other side will power up the DHT22 sensor 5 seconds before the target time ,read the sensor and fill up the transmit fifo buffer. The beauty of the shockburst method is that the arduino just wait for the raspberry Pi to transmit and the fifo buffer will be send automatically to the Pi without any intervention of the arduino.
Presently I just power up/down the DHT22 sensor , but I will eventually put the RF24L01 and the Arduino mode into sleep mode when I don't need them. The purpose is to reduce power consumption to a minimal. This way I could use AA batteries which will last very long.
So right now the python code is working and display the sensor data on the terminal.
I use this github to get the library to run the
nRF24L01 on python
https://github.com/Blavery/lib_nrf24
And this is the Python code
Code: Select all
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Example program to send packets to the radio link
#
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
from lib_nrf24 import NRF24
import time
import spidev
import binascii
import numpy
from struct import *
STRUCT_TYPE_GETDATA=0
STRUCT_TYPE_INIT=1
STRUCT_TYPE_DHT22=2
class DHT22Data:
time = None
humidity = 0
temperature =0
voltage=0
valid=False
class RF_Device:
def __init__(self, deviceAddress, nextTime=60):
self.deviceAddress=deviceAddress
self.nextTime=nextTime;
self.lastConnectionTime= time.time()
self.nextConnectionTime= self.lastConnectionTime
self.xdata = [0,0,0]
self.rdata = ''
def isTimeOut(self):
return (time.time() > self.nextConnectionTime)
def readSensorAddress(self):
buffer = '{:02X}'.format(self.deviceAddress[0])
for i in range(1,5,1):
buffer += ':{:02X}'.format(self.deviceAddress[i])
return buffer
def unpackDHT22Data(self , buffer):
dht22 = DHT22Data
if len(buffer) != 15:
return None
try:
self.rdata = unpack('<sBBBLBHHH',''.join(map(chr,buffer)))
dht22.time = self.rdata[4]
dht22.valid = self.rdata[5]!=0
dht22.voltage = self.rdata[6]/1000.0
dht22.temperature = self.rdata[7]/10.0
dht22.humidity = self.rdata[8]
return dht22
except:
return None
def getData(self):
if( not self.isTimeOut()):
return None
# print("timeout={}".format(self.nextTime))
self.nextConnectionTime += self.nextTime
#buildpacket
packet = '*'
packet += chr(10) #get packet size
packet += chr(STRUCT_TYPE_GETDATA)
packet += chr(0) #0 mean master
packet += pack('<L', numpy.uint32(time.time())) #get current time
packet += pack('<H', numpy.uint16(self.nextTime *10)) #get next time reading
# print("send : {}".format(list(packet)))
radio.openWritingPipe(self.deviceAddress)
radio.write(packet)
if True:
if radio.isAckPayloadAvailable():
in_buffer=[]
radio.read(in_buffer,radio.getDynamicPayloadSize())
validFlag= False
if len(in_buffer)>4:
# check first four bytes
if in_buffer[0] == ord('*'):
if in_buffer[2] == STRUCT_TYPE_INIT:
#sensor is valid but just boot
print("Sensor {} - {} - Just boot".format(self.readSensorAddress(),time.ctime()))
validFlag=True
if in_buffer[2] == STRUCT_TYPE_DHT22:
dht22 = self.unpackDHT22Data(in_buffer)
if dht22 != None:
if dht22.valid:
print("Sensor {} - {} VCC:{}V T:{}C H:{}%".format(self.readSensorAddress(),time.ctime(dht22.time),dht22.voltage,dht22.temperature,dht22.humidity))
else:
print("Sensor {} - {} VCC:{}V Unable to read DHT22 sensor".format(self.readSensorAddress(),time.ctime(dht22.time),dht22.voltage))
validFlag=True
# except:
# print("Unable to unpack!Bad packet")
if not validFlag:
print("Sensor {} - {} Invalid packet!".format(self.readSensorAddress(),time.ctime()))
else:
print("Sensor {} - {} time out!".format(self.readSensorAddress(),time.ctime()))
masterAddress = [0xe7, 0xe7, 0xe7, 0xe7, 0xe7]
device = [RF_Device([0xc2,0xc2,0xc2,0xc2,0xc3],10)]
radio = NRF24(GPIO, spidev.SpiDev())
radio.begin(0, 17)
time.sleep(1)
radio.setRetries(15,15)
radio.setPayloadSize(32)
radio.setChannel(78)
radio.setDataRate(NRF24.BR_1MBPS)
radio.setPALevel(NRF24.PA_MAX)
radio.setAutoAck(True)
radio.enableDynamicPayloads()
radio.enableAckPayload()
radio.openWritingPipe(device[0].deviceAddress)
radio.openReadingPipe(1, masterAddress)
radio.printDetails()
time.sleep(1)
try:
while True:
for i in device:
if(i.isTimeOut()):
i.getData();
time.sleep(0.01)
except KeyboardInterrupt:
radio.stopListening();
radio.powerDown();
raise
and this is the result display
Code: Select all
pi@Pi2 ~/lib_nrf24 $ sudo python s4.py
/home/pi/lib_nrf24/lib_nrf24.py:377: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
self.GPIO.setup(self.ce_pin, self.GPIO.OUT)
STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1 = 0xc2c2c2c2c3 0xe7e7e7e7e7
RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR = 0xc2c2c2c2c3
RX_PW_P0-6 = 0x20 0x20 0x00 0x00 0x00 0x00
EN_AA = 0x3f
EN_RXADDR = 0x03
RF_CH = 0x4e
RF_SETUP = 0x07
CONFIG = 0x0c
DYNPD/FEATURE = 0x3f 0x06
Data Rate = 1MBPS
Model = nRF24l01+
CRC Length = 16 bits
PA Power = PA_HIGH
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:36:41 2015 - Just boot
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:36:45 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:36:53 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:37:03 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:37:13 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:37:23 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:37:33 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:37:43 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:37:53 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:38:03 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:38:13 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:38:23 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:38:33 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:38:43 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:38:53 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:39:03 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:39:13 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:39:23 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:39:33 2015 VCC:4.957V T:19.3C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:39:43 2015 VCC:4.957V T:19.4C H:16%
Sensor C2:C2:C2:C2:C3 - Sun Mar 22 22:39:53 2015 VCC:4.957V T:19.3C H:16%
For the arduino code I use those code for the
nRF24L01 and the DHT22 library
http://maniacbug.wordpress.com/2011/11/ ... rted-rf24/
http://provideyourown.com/2012/secret-a ... y-voltage/
https://github.com/RobTillaart/Arduino.git
And now my Arduino code
Code: Select all
/*
Copyright (C) 2015 Daniel Perron
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
Read DHT22 sensor using a nRF24L01 sensor base on J.Coliz code
*/
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
//2014 - TMRh20 - Updated along with Optimized RF24 Library fork
*/
/**
* Example for Getting Started with nRF24L01+ radios.
*
* This is an example of how to use the RF24 class to communicate on a basic level. Write this sketch to two
* different nodes. Put one of the nodes into 'transmit' mode by connecting with the serial monitor and
* sending a 'T'. The ping node sends the current time to the pong node, which responds by sending the value
* back. The ping node can then see how long the whole cycle took.
* Note: For a more efficient call-response scenario see the GettingStarted_CallResponse.ino example.
* Note: When switching between sketches, the radio may need to be powered down to clear settings that are not "un-set" otherwise
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
#include "dht.h"
#define DHT_PIN 2
#define DHT_POWER_PIN 3
//DHT22 class
dht DHT;
short temperature= 32767;
unsigned short humidity = 32767;
// Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(8,7);
#define UNIT_ID 0xc3
const uint64_t pipes[2] = { 0xc2c2c2c2c3 , 0xe7e7e7e7e7 }; // Radio pipe addresses for the 2 nodes to communicate.
// Set up roles to simplify testing
boolean role; // The main role variable, holds the current role identifier
boolean role_ping_out = 1, role_pong_back = 0; // The two different roles.
unsigned long Count=0;
void setup() {
// Set pin for DHT22 power
pinMode(DHT_POWER_PIN, OUTPUT);
digitalWrite(DHT_POWER_PIN, LOW);
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/GettingStarted/\n\r");
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
// Setup and configure rf radio
//radio.setChannel(0x60);
radio.begin(); // Start up the radio
radio.setPayloadSize(32);
radio.setChannel(0x4e);
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(15,15); // Max delay between retries & number of retries
radio.enableDynamicPayloads();
radio.enableAckPayload();
//role = role_ping_out; // Become the primary transmitter (ping out)
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
radio.startListening(); // Start listening
radio.stopListening();
radio.printDetails(); // Dump the configuration of the rf unit for debugging
radio.startListening();
}
enum cycleMode {ModeInit,ModeListen,ModeWriteData,ModeWait};
cycleMode cycle= ModeInit;
#define STRUCT_TYPE_GETDATA 0
#define STRUCT_TYPE_INIT_DATA 1
#define STRUCT_TYPE_DHT22_DATA 2
typedef struct
{
char header;
unsigned char structSize;
unsigned char structType;
unsigned char txmUnitId;
unsigned long currentTime;
unsigned short nextTimeReading;
char Spare[22];
}RcvPacketStruct;
typedef struct
{
char header;
unsigned char structSize;
unsigned char structType;
unsigned char txmUnitId;
unsigned long stampTime;
unsigned char valid;
unsigned short voltageA2D;
unsigned short temperature;
unsigned short humidity;
}TxmDHT22PacketStruct;
unsigned long currentDelay;
unsigned long targetDelay;
RcvPacketStruct RcvData;
TxmDHT22PacketStruct Txmdata;
unsigned char * pt = (unsigned char *) &RcvData;
unsigned char rcvBuffer[32];
void PrintHex(uint8_t *data, uint8_t length) // prints 16-bit data in hex with leading zeroes
{
char tmp[32];
for (int i=0; i<length; i++)
{
sprintf(tmp, "0x%.2X",data[i]);
Serial.print(tmp); Serial.print(" ");
}
}
bool readSensor(void)
{
// power Sensor UP
digitalWrite(DHT_POWER_PIN, HIGH);
// Wait 2 sec
delay(2000);
// Now let's read the sensor twice
// since the first one will be bad
DHT.read(DHT_PIN);
delay(1000);
int rcode = DHT.read(DHT_PIN);
// power off DHT22
digitalWrite(DHT_POWER_PIN,LOW);
return (rcode == DHTLIB_OK);
}
//From http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
unsigned short readVcc() {
// Read 1.1V reference against AVcc
// set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Start conversion
while (bit_is_set(ADCSRA,ADSC)); // measuring
uint8_t low = ADCL; // must read ADCL first - it then locks ADCH
uint8_t high = ADCH; // unlocks both
long result = (high<<8) | low;
result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
return (unsigned short) result; // Vcc in millivolts
}
void loop(void){
int loop;
unsigned long deltaTime;
/****************** Ping Out Role ***************************/
if(cycle==ModeInit)
{
Count++;
Txmdata.header='*';
Txmdata.structSize= sizeof(TxmDHT22PacketStruct);
Txmdata.structType=STRUCT_TYPE_INIT_DATA;
Txmdata.txmUnitId = UNIT_ID;
Txmdata.stampTime=0;
Txmdata.valid=0;
Txmdata.temperature=0;
Txmdata.humidity=0;
Txmdata.voltageA2D=0;
radio.writeAckPayload(1,&Txmdata,sizeof(TxmDHT22PacketStruct));
cycle=ModeListen;
}
if(cycle==ModeListen)
{
if(radio.available())
{
int rcv_size= radio.getDynamicPayloadSize();
radio.read( &RcvData,rcv_size);
Serial.print("T:" );
Serial.print(RcvData.currentTime);
Serial.print(" Next reading in (1/10 sec): ");
Serial.print(RcvData.nextTimeReading);
Serial.print("\n");
PrintHex(pt,rcv_size);
Serial.print("\n");
currentDelay = millis();
if(RcvData.nextTimeReading > 50)
{
targetDelay = RcvData.nextTimeReading*100 - 5000UL;
cycle = ModeWait;
}
else
cycle = ModeWriteData;
}
}
if(cycle== ModeWait)
{
deltaTime = millis() - currentDelay;
if(deltaTime >= targetDelay)
cycle = ModeWriteData;
}
if(cycle==ModeWriteData)
{
Txmdata.valid=1;
Txmdata.stampTime=RcvData.currentTime;
Txmdata.header='*';
Txmdata.structSize= sizeof(TxmDHT22PacketStruct);
Txmdata.structType=STRUCT_TYPE_DHT22_DATA;
Txmdata.txmUnitId = UNIT_ID;
Txmdata.stampTime=RcvData.currentTime + (deltaTime / 1000);
Txmdata.valid=0;
Txmdata.temperature=32767;
Txmdata.humidity=32767;
Txmdata.voltageA2D=readVcc();
if(readSensor())
{
Txmdata.temperature = (short) floor(DHT.temperature * 10.0);
Txmdata.humidity = (short) floor(DHT.humidity);
Txmdata.valid = 1;
}
radio.writeAckPayload(1,&Txmdata,sizeof(TxmDHT22PacketStruct));
cycle=ModeListen;
}
}