From Overflow

The DIY-couple-of-bucks Arduino weather station running on the protocol weather1 which can be recognized by Pimatic’s homeduino without any issues!

Hardware:

  • Arduino (or just an Atmega on a breadboard)
  • 433MHz Transmitter
  • DHT22 (others should work as well)

The projects outcome

I personally think it is a good way to enable the community to build cheap sensors which don’t require much parts.

I know my work isn’t perfect as it is, there is lots of stuff that needs to be done like reading battery voltage and transmitting that as well, but here is a first glance at the code:

/**
* Weather1 spoof by Florian Leitmann
* 14th June 2015
* Made for Pimatic
* Tested to work with:
* - FS1000A RF transmitter
* - DHT22 temperature/humidity sensor
* - Homeduino on Pimatic
*/

//include the library to work with the DHT
#include "DHT.h"

//The values below have been identified by the documentation on weather1
#define SIGNAL_BREAK 456
#define SIGNAL_SHORT 1990
#define SIGNAL_LONG 3940
#define SIGNAL_STOP 9236
#define REPEATS 7

#define RFPIN 3       //Pin that the RF transmitter is connected to
#define RFPWRPIN 6    //Pin that the power of the transmitter is connected to
#define DHTPIN 4      //Pin that the DHT data is connected to
#define DHTPWRPIN 5   //Pin that the DHT power is connected to
#define DHTTYPE DHT22 //DHT11 or DHT21 (AM2301) or DHT22 (AM2302)
DHT dht(DHTPIN, DHTTYPE);
int MODULE_ID = 1;    //Used to identify the module in pimatic (1-255)
int CHANNEL = 1;      //Multiple channels can be used (can be 1 - 4)
int TEMP_UNIT = 'C';  //may be set to F
int WAIT_TIME = 10;    //in seconds (minimum: 3 secs)

/**
* This is a template of the binary message that will be send encoded
* by pulses of the RF transmitter
* Here is what the bits mean
* 0101 | 11010000 | 00 | 00 | 000100001001 | 00111101
*  ?        ID      BT   CH      Temp.        Humid.
*
* The temperature in this example is 26.5° (but sended at 265) and will
* be decoded in Pimatic again to the correct value.
* The value of the relative humidity is 65%
*/
byte message[] = {
  0,1,0,1,1,0,0,0,1,1,0,0,1,1,0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,1,1,1,1,1,1
};

void setup() {
  pinMode(RFPIN, OUTPUT);
  pinMode(RFPWRPIN, OUTPUT);
  pinMode(DHTPWRPIN, OUTPUT);
  pinMode(13, OUTPUT); //LED Pin
  setMessage(MODULE_ID, 4, 11);
  setMessage(CHANNEL-1, 14, 15);
  dht.begin();
}

/*
* @loop()
* turn on the hardware, send the message (other functions get called)
* to retrieve the data, so look below, then switch the hardware off
* and wait for the next cycle
*/
void loop() {
    setHardware(1);
    sendMessage();
    setHardware(0);
    delay((WAIT_TIME-2)*1000); //adjusted due to necessary wait from DHT
}

/*
* @setHardware(byte on_off)
* turn the attached devices either on or off, whatever
* you need right now
*/
void setHardware(byte on_off){
  if(on_off == 1){
    digitalWrite(DHTPWRPIN, HIGH);
    digitalWrite(RFPWRPIN, HIGH);
  } else {
    digitalWrite(DHTPWRPIN, LOW);
    digitalWrite(RFPWRPIN, LOW);
  }
}

/*
* @sendBit(byte b)
* takes a given byte which is either 1 or 0 and then sends it
* over the air using the breaks necessary for pimatic to recognize
* the profile of the a weather1 station
*/
void sendBit(byte b) {
  
  if (b == 0) {
    digitalWrite(RFPIN, HIGH);
    delayMicroseconds(SIGNAL_BREAK);
    digitalWrite(RFPIN, LOW);
    delayMicroseconds(SIGNAL_SHORT);
  }
  else {
    digitalWrite(RFPIN, HIGH);
    delayMicroseconds(SIGNAL_BREAK);
    digitalWrite(RFPIN, LOW);
    delayMicroseconds(SIGNAL_LONG);
  }
}

/*
* @sendTerminator()
* This method sends Arnold Schwarzenegger back in time. Just kidding,
* actually it does deliver the long break to show the end of the
* message[]
*/
void sendTerminator(){
    digitalWrite(RFPIN, HIGH);
    delayMicroseconds(SIGNAL_BREAK);
    digitalWrite(RFPIN, LOW);
    delayMicroseconds(SIGNAL_STOP);
    digitalWrite(RFPIN, HIGH);
    digitalWrite(RFPIN, LOW);
}

/*
* @sendMessage()
* execute the getDHTvalues() method to get some input in the
* message[] and then send the message X times using the sendBit() method
* followed by the terminator pulse 
*/
void sendMessage() {
  getDHTvalues();
  for (byte i = 0; i < REPEATS; i++) {
    digitalWrite(13, HIGH); //LED PIN
    for (byte i = 0; i < sizeof(message); i++){
      sendBit(message[i]);
    }
    digitalWrite(13, LOW);
  sendTerminator();
  }
}

/*
* @setMessage(int val, int startPos, int endPos)
* convert an integer to binary representation and
* write the output to the locations specified in the
* message[]
*/
void setMessage(int val, int startPos, int endPos){
  int result[12];
  int theValue = val;
  
  for (byte i = 0, j = 11; i < 12; ++i, j--) {
      result[j] = theValue & (1 << i) ? 1 : 0;
  }
  
  for (byte i = endPos, j=11; i > startPos-1; i--,j--){
      message[i] = result[j];
  }
}

/*
* @getDHTvalues()
* wait for two seconds to read the values of the DHT and
* replace their counterparts in the message[]
*/
void getDHTvalues(){
  delay(2000); //DHT needs 2 seconds to get started
  int h = (int) dht.readHumidity();
  int t;
  if(TEMP_UNIT == 'C'){
    t = (int) (dht.readTemperature() * 10);
  } else {
    t = (int) (dht.readTemperature(true) * 10);
  }
  //if the values could not be red
  if (isnan(h) || isnan(t)) {
    setMessage(0, 16, 27); //Temperature
    setMessage(0, 28, 35); //Humidity
  } else {
    setMessage(t, 16, 27); //Temperature
    setMessage(h, 28, 35); //Humidity
  }
}

Listening using the debug mode in Pimatic on the homeduino you receive:

Homeduino Output

This is how the device is to be configured in Pimatic:

{
      "id": "fakeWeather",
      "name": "Faked Weather Station",
      "class": "HomeduinoRFTemperature",
      "protocols": [
        {
          "name": "weather1",
          "options": {
            "id": 1,
            "channel": 1
          }
        }
      ]
}

And once you put the device in Pimatic you will receive such an output:

Pimatic overview