2017-07-05

RF Temperature Sensor

This is the description of a sensor board that measures the temperature and transmits it over 433.92MHz radio. It uses the protocol for the weather1 sensor in pimatic/rfcontroljs [1]. Four separate temperature sensors can be connected to the same board.

Components

Arduino Pro Mini 5V [2]
TX433N Transmitter [3]
KTY84/150 Temperature Sensor [4]
1 kOhm Resistor
Coil Loaded Antenna [5]
9V Battery Connector
2x 1 MOhm Resistor

Assembly

The Arduino is the backbone of the construction. Connect the battery connector to RAW and GND.

Analog 5 is used to monitor the battery health. The two 1 MOhm resistors form a voltage divider to get below 5V on the analog input. Connect one resistor between RAW and Analog 5. Connect the other resistor between Analog 5 and GND.

The KTY84 and the resistor forms a voltage divider. KTY84 connects to GND and one of Analog 0, 1, 2 or 3. The resistor connects to the same Analog and VCC.

TX433N is powered by VCC and GND on the Arduino. Connect TX433N Data to Digital 2.

Connect the coil loaded antenna to Ant.

Configuration

The board is configured with messages sent on the serial port (115200 bps). The following values can be set.

X0: Exact resistance of the 1 kOhm Resistor
X1: Exact resistance of KTY84 at zero degrees Celsius
02: Id 0-255 (weather1)
03: Measurement Interval 0-32767 (ms)
04: Low battery warning level 0-1023

where X selects one of the analog inputs 0, 1, 2 or 3. Each sensor transmit on separate weather1 channels 1, 2, 3 and 4. All sensors have the same id and measurement interval.

Example: To set the analog in 3 KTY84 zero degree resistance to 509 Ohm, send the following message, ending with newline.

31:509

The temperature measured by this KTY84 will transmit on channel 4.

Calibration

To calibrate the sensor, first measure the resistance of the 1 kOhm resistor and write the value to config X0. Then adjust config X1 until the measured temperature matches the value of a reference temperature. The sensor is disabled when X0 is zero.

References

[1] https://github.com/pimatic/rfcontroljs
[2] https://www.arduino.cc/en/Main/ArduinoBoardProMini
[3] https://www.velleman.eu/products/view/?id=350619
[4] http://www.nxp.com/docs/en/data-sheet/KTY84_SER.pdf
[5] http://www.instructables.com/id/433-MHz-Coil-loaded-antenna

Source Code

/*
  Copyright (C) 2017  Marcus Andersson

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see .
*/

#include "EEPROM.h"

// Digital
int ledPin = 13;
int txPin = 2;

// Analog
int thermoPin = 3;

// Pulse period time, 10 microsecond steps
#define PT 48

// Number of config values
#define NCONFIG 5

// EEPROM stored configuration data
struct Config {
  int data[NCONFIG];
};
Config config;

#define BUFLEN 100
byte packet[BUFLEN];
byte length = 0;

void printConfig() {
  for (int i = 0; i < NCONFIG; i++) {
    Serial.print(i);
    Serial.print(": ");
    Serial.println(config.data[i]);
  }
}

void setConfig(int i, int val) {
  config.data[i] = val;
  EEPROM.put(0, config);
}

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(txPin, OUTPUT);
  Serial.begin(115200);
  EEPROM.get(0, config);
  printConfig();
}

void send(int temp, byte id, byte ch) {
  int i, j;
  unsigned long t0;
  unsigned long periods;
  byte data[36] = {
    0, 1, 0, 1,
    1, 1, 0, 1, 0, 0, 0, 0, // id
    1, 1, // batt
    0, 1, // channel
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // temp
    0, 0, 0, 0, 0, 0, 0, 0 // hum
  }; 
 
  // Write id
  for (i = 0; i < 8; i++) {
    data[4+i] = (id >> (7-i)) & 1;
  }
 
  // Write channel
  data[14] = ((ch-1) >> 1) & 1;
  data[15] = ((ch-1) >> 0) & 1;
 
  // Write temp
  data[16] = (temp < 0) ? 1 : 0;
  for (i = 1; i < 12; i++) {
    data[16+i] = (temp >> (11-i)) & 1;
  }
 
  digitalWrite(ledPin, HIGH);   // sets the LED on

  periods = 0;
  t0 = micros();
 
  digitalWrite(txPin, HIGH); periods += 8;
  delayMicroseconds(max(10000, t0 + periods*PT - micros()));
  digitalWrite(txPin, LOW); periods += 230;
  delayMicroseconds(max(10000, t0 + periods*PT - micros()));

  for (j = 0; j < 4; j++) {
    for (i = 0; i < 36; i++) {
      digitalWrite(txPin, HIGH); periods += 8;
      delayMicroseconds(max(10000, t0 + periods*PT - micros()));
      digitalWrite(txPin, LOW); periods += 4*10 + 4*11*data[i];
      delayMicroseconds(max(10000, t0 + periods*PT - micros()));
    }

    digitalWrite(txPin, HIGH); periods += 8;
    delayMicroseconds(max(10000, t0 + periods*PT - micros()));
    digitalWrite(txPin, LOW); periods += 230;
    delayMicroseconds(max(10000, t0 + periods*PT - micros()));
  }
  digitalWrite(ledPin, LOW);    // sets the LED off
}

void loop()
{
  static unsigned long sendTime = millis() - config.data[4];
 
  if (millis() - sendTime > config.data[4]) {
    long r0 = config.data[0];
    long r1 = config.data[1];
    long id = config.data[2];
    long ch = config.data[3];
    long s = analogRead(thermoPin);
    long r = r0*s/(1023-s);
    int t = (r-r1)*2;
   
    sendTime += config.data[4];
    send(t, id, ch);
   
    Serial.print(s);
    Serial.print(" ");
    Serial.println(t);
  }

  while (Serial.available() > 0) {
    int d = Serial.read();
    packet[length++] = d;
    if (d == 10 || length >= BUFLEN) {
      int p = 0;
      int i = packet[p++] - '0';
      if (i >= 0 && i < NCONFIG) {
        int v = 0;
        int d = packet[p++];
        d = packet[p++];
        while (d >= '0' && d <= '9') {
          v = v*10 + d - '0';
          d = packet[p++];
        }
        setConfig(i, v);
        printConfig();
      }
      length = 0;
    }
  } 
}


No comments: