0

I have installed Domoticz on Raspberry Pi and bought an RfxCom 433MHz emitter/receiver. It works well for example with Chacon DiO 54781 door sensor. I want to create my own sensor with Arduino that would be recognized by Domoticz as a native RF 433MHz device. In first place, I want to make a flooding sensor, I also need an On/Off information. I would like to implement X10 protocol because it seems to be the simplest one.

1

I finally found a documentation about RF X10 protocol: X10 RF Receiver.pdf

With following Hardware :

I've created the following working code for Arduino Nano :

/*
* Custom sensor (base code)
*
* Emission in RF 433MHz with the X10 protocol for Domoticz
*
* Hardware :
*   Arduino Pro Mini 5V         (4€)        https://www.amazon.fr/gp/product/B00QPUEFNW/ref=oh_aui_search_detailpage?ie=UTF8&psc=1
*   RF 433MHz emitter/receiver  (3€)        https://www.amazon.fr/HDigiWorld-metteur-cepteur-commande-Arduino/dp/B00JTQI39G/ref=sr_1_3?s=computers&ie=UTF8&qid=1470813610&sr=1-3&keywords=433
*       Note: only the emitter is used
*   3 wires : VCC, GND, Signal (on Arduino pin 2)
*
* Documentation found for RF X10: http://www.printcapture.com/files/X10_RF_Receiver.pdf
*
* Example of malformed data received in RfxMngr in mode "nodec" (before this code was correctly debugged) :
*
*       Packettype        = UNDECODED RF Message
*       UNDECODED NEC:1C515C86F0      
*
*
* Correct data that is now receveived by RfxMngr with this program :
*
*------------------------------------------------
*       Packettype    = Lighting1
*       subtype       = X10
*       Sequence nbr  = 13
*       housecode     = D
*       unitcode      = 1
*       Command       = On
*       Signal level  = 7  -64dBm
*------------------------------------------------
*       Packettype    = Lighting1
*       subtype       = X10
*       Sequence nbr  = 14
*       housecode     = D
*       unitcode      = 1
*       Command       = Off
*       Signal level  = 7  -64dBm
*------------------------------------------------
*/

const int pin_emit = 2;         // Signal pin for RF433 emitter
const int pin_led = 13;         // Internal LED : it will be ON when the "On" command is sent in RF, and OFF the the "Off" command is sent (changed each 60s)

const unsigned int X10_A1_ON = 0x00;        
const unsigned int X10_A1_OFF = 0x20;

const unsigned int X10_address = 5;     // this is Housecode. In my case 5 results in "D" house code
unsigned int X10_data = X10_A1_ON;      // command. I have implemented only On/Off for unit code 1


void setup() {
  pinMode(pin_led, OUTPUT);
  pinMode(pin_emit, OUTPUT);
  digitalWrite(pin_emit, LOW);
}




/**
* Bit to 0 : 1.125ms between rising edges, so before next bit
*/
void X10_sendBit_zero()
{
  digitalWrite(pin_emit, HIGH);
  delayMicroseconds(555);       // Arbitrary value: I took around 1.125ms divided by two for the "VCC" state.
  digitalWrite(pin_emit, LOW);
  delayMicroseconds(570);       // Total 555+570 : 1125µs = 1.125ms
}


/**
* Bit à 1 : 2.25ms entre les "rising edges"
*/
void X10_sendBit_one()
{
  digitalWrite(pin_emit, HIGH);
  delayMicroseconds(555);       // Arbitrary value: I took around 1.125ms divided by two for the "VCC" state.
  digitalWrite(pin_emit, LOW);
  delayMicroseconds(1695);      // Total 555+1695 : 2250µs = 2.250ms
}



void X10_send8bits(unsigned int data)
{
  // - Send the 8 bits, and then the complementary of the 8 bits.
  // from documentation: "Within each byte, bit7 is received first and bit0 last"
  int mask = 0x80;
  for(int i = 0; i < 8; i++)
  {
    int bit = mask & data;
    if (bit == 0)
      X10_sendBit_zero();     
    else
      X10_sendBit_one();

    mask = mask >> 1;
  }
}


/**
* Sending a byte consists of sending this byte, and then sending the opposite of the same byte.
* As we send the opposite as well as the data, the total duration is always the same : 8 * (1.125ms+2.250ms) = 8 * 3.375 = total of 27ms
*/
void X10_sendByte(unsigned int data)
{
  X10_send8bits(data);
  X10_send8bits(~data);
}




/**
* Send a complete X10 packet
*
* Total duration :
* (9ms + 4.5ms) + (27ms + 27ms) + 0.555ms + 40ms = 108.055 ms
*  from doc: "It appears, from articles on the 'net, that other people have seen a range from 95 msec to 116 msec for various transmitters and that standard X-10 transceivers can tolerate timing variations of 30-35% from nominal."
*/
void X10_sendState_once(unsigned int data)
{


  // - Header
  digitalWrite(pin_emit, HIGH); // "Burst" de 9ms
  delayMicroseconds(9000);
  digitalWrite(pin_emit, LOW); // Silence de 4.5ms
  delayMicroseconds(4500);

  // - Data
  X10_sendByte(0x50); // - Address
  X10_sendByte(data); // - Data

  // - Send a last rising edge to validate last bit
  digitalWrite(pin_emit, HIGH);
  delayMicroseconds(555);       // Arbitraty value (but always the same), for "VCC" state.

  // - Footer
  digitalWrite(pin_emit, LOW); // Silence de 40ms pour signifier la fin de l'émission
  delayMicroseconds(40000);

}


/**
* Send a complete packet multiple times (this X10 protocol has not ACK))
* From doc: "Most X-10 RF transmitters send a minimum of five copies of the code separated by 40 msec silences although some can send single bursts." 
*
*  5 times 108.055ms = 540.275 ms, half a second
*/
void X10_sendState(unsigned int data)
{
  // - "clean" to be sure to have a zero for the first rising edge on init
  digitalWrite(pin_emit, LOW);
  delay(1);

  // - Send 5 time complete packet
  for(int repeat=0 ; repeat<5 ; repeat++)
    X10_sendState_once(data);

}





void loop() {

  if(X10_data == X10_A1_ON)
    digitalWrite(pin_led, HIGH);
  else
    digitalWrite(pin_led, LOW);
  X10_sendState(X10_data);
  delay(60000);              // 1 minute

  // - I change state each 60 seconds to see changes in Domoticz
  if(X10_data == X10_A1_ON)
    X10_data = X10_A1_OFF;
  else
    X10_data = X10_A1_ON;
}

By changing House code and data, it is now possible to create our own RF sensors.

  • Just to say, since my previous answer, I concluded it was too much effort for each new sensor to find how to implement a new protocol. So I finally tried and adopted "MySensors", because I only need to feed it with payload. – Elo May 29 '17 at 11:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.