Introduction: RF Temperature Sensors to Ethernet

About: Programmer since C64

The goal of this project has been the study of an house indoor and outdoor temperatures. In particular the original goal was to make a tool with simple installation and low maintenance.

The first solution I've found has been the use of an Arduino Uno connected to the Internet through an Ethernet Shield in combination with a temperature sensor directly connected to the same board. This solution did not meet the requirement of simple installation: the Ethernet cable was a first limitation forcing an installation near the router. The second limitation was, of course, powering this device: an outdoor installation would have required an electric socket, not always available in the right place.

The final solution has been the creation of a receiver in conjunction with a certain numbers of transmitter using radio frequency at 433 MHz. Thanks to this inexpensive solution, both in terms of power and money, now I have a system that give me the possibility of collecting temperature but also every physical quantity I would detect: voltage, humidity, open doors, etc.

To achieve low consumption the transmitter uses a simplified version of Arduino, that somewhere is called Bareduino: in brief, the main component of this device is an ATMEGA328P-PU and some others basic electric components.

Step 1: Step 1: the Receiver

The receiver is made of the following components:

  1. Arduino UNO R3
  2. Ethernet Shield Wiznet W5100 (I've used a compatible version)
  3. RF433 Rx module
  4. 1 green LED
  5. 1 red LED
  6. 2 220 Ohm resistors
  7. 1 power supplier
  8. wires
  9. bread board
  10. a coil wire for the antenna

The receiver always waits for a RF transmitter to transmit a string like this:

MC00225551243710000469361
+---+-+-+----++-+-----+-+
1   2 3 4    56 7     8
  1. transmitter device identifier
  2. session identifier
  3. counter in this session
  4. temperature value
  5. sign of the temperature
  6. free
  7. voltage value
  8. CRC8

The receiver device will append its own identifier to this string, both with its own counter. The final string will be, for instance:

MC00225551243710000469361MC00164
+-----------------------+----+-+ 
1                       2    3
  1. the received string
  2. the receiver identifier
  3. counter

This string will be transmitted to a web service in the cloud.

Attached there's the Arduino Sketch

Step 2: Step 2: the Transmitter

The transmitter is made of the following components:

  1. ATMEGA328P-PU with Arduino bootloader
  2. Crystal 16MHz
  3. 2 22 pF ceramic capacitors
  4. RF433 Tx module (you can buy all 4 components in kit)

  5. 1 battery holder for 3 batteries

Using an Arduino would have result in a very fast battery discharge, while the final goal was to have a temperature logger with a long independent life. Thanks Google, I've found and adapted a project called Bareduino which goal was just to have a minimalistic board that can be debugged (more or less) with the same tools used for Arduino.

The figure shows the final device configuration drawn using Fritzing.

The code to load into the ATM328 is this

#include <LowPower.h>
#include <RH_ASK.h> #include <SPI.h> #include <OneWire.h> #include <DallasTemperature.h> OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); RH_ASK driver; // Michele Carfora 17.II.2017 // Voltage and Temperature RF 433MHz Transmitter long ctr; // Transmission counter String session; // Session identifier char txID[6] = "MC003"; // Device identifier byte errore; // Last error (not used) bool initID = false; // int frequenza = 30; // Time between a transmission and another long lasttemp; String RRes; // String to transmitt void sessionid() { // generate a random Session identifier // It can be used to identify the start of a transmission sequence randomSeed(analogRead(0)); int nres = random(0, 99); char res[3]; sprintf(res, "%02i", nres); session = String(res); } long temperatura000() { // here the code reads the temperature value from the sensor sensors.requestTemperatures(); // Send the command to get temperatures float temper; temper=sensors.getTempCByIndex(0); long res; res = (long)(temper * 1000); lasttemp = res; return res; } //CRC-8 by Dallas/Maxim //GNU GPL 3.0 byte CRC8(const byte *data, byte len) { byte crc = 0x00; while (len--) { byte extract = *data++; for (byte tempI = 8; tempI; tempI--) { byte sum = (crc ^ extract) & 0x01; crc >>= 1; if (sum) { crc ^= 0x8C; } extract >>= 1; } } return crc; } void rileva() { // Does the work ctr++; if (ctr > 99) { ctr = 0; }</p><p> String tmpres; long riltemp = temperatura000(); char res[6]; char segno = '1'; char ril[3]; int parz; byte crc; char bcrc[3]; byte buf[24]; char vcc[7];</p><p> // segno = 0 stands for a negative temperature // segno = 1 stands for a positive temperature if (riltemp < 0) { segno = '0'; }</p><p> sprintf(res, "%05d", abs(riltemp)); sprintf(ril, "%02d", ctr); sprintf(vcc, "%06d", vccVoltage()); tmpres = String(txID) + session + String(ril) + res + String(segno) + "00" + String(vcc); </p><p> tmpres.getBytes(buf, 23); crc = CRC8(buf, 23); sprintf(bcrc, "%02X", crc); </p><p> RRes = tmpres + String(bcrc); } int inviaeattendi(String messaggio) { int lmes = messaggio.length() + 1; char buf[lmes]; messaggio.toCharArray(buf, lmes); driver.send((uint8_t *)buf, lmes); driver.waitPacketSent(); return lmes; } // <a href="https://code.google.com/archive/p/tinkerit/wikis/SecretVoltmeter.wiki" rel="nofollow"> https://code.google.com/archive/p/tinkerit/wikis/...> long vccVoltage() { long result; // Read 1.1V reference against AVcc ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 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 AVcc in mV return result; } void sleepMinutes() // ATMEGA328 sleeps for 8 seconds and wait until the frequenza has been reached { int ltsl = (int)(7.5 * (float)frequenza); for (int i = 0; i < ltsl; i++) { LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); } } void setup() { ctr = 0; sessionid(); Serial.begin(9600); // Debugging only if (!driver.init()) Serial.println("init failed");</p><p> // Start up the library sensors.begin(); } void loop() { rileva(); int rt; rt = inviaeattendi(RRes); Serial.println("Ident: " + String(txID)); Serial.println("Session: " + session); Serial.println("cont: " + String(ctr)); Serial.println("temp: " + String(lasttemp)); Serial.println("RRES: " + RRes); Serial.println("Lunghezza: " + String(rt)); Serial.println("Inviato pacchetto."); Serial.println(vccVoltage()); sleepMinutes(); }