Has anyone successfully made an Arduino based custom ZigBee device?

I’ve made myself a rough Arduino based controller for a fan that I already had lying around. While I haven’t actually wired it into the fan yet, bench testing suggests that it will mimic the existing controls pretty well - with a push button to cycle between power levels and a push button to control oscillation (on or off) I also have a DS18B20 temperature connected to the Arduino, but so far I’m not doing anything with the temperature data.

Now for the need to unnecessarily over complicate things. Most of my home automation devices are connected to HA via ZigBee (ZHA) using an XBee connected to my HA machine via USB using a Grove development board. I also have a couple of extra XBees…

So far I have managed to connect an XBee to the Arduino and communicate with another one in coordinator mode (so far just one way communication) using the Arduino serial connection. What I would really like to do though is connect to HA, using ZHA to give me the option to automate my fan, and use the connected temperature sensor within HA too. Unfortunately I’ve run out of talent as far as that bit goes.

I want to do this with the existing hardware I have, and have no interest in doing this with an ESP device, using WiFi. I have no desire to add any extra WiFi devices to my network.

I’ve looked here:
Building own zigbee device using arduino + zigbee shield which ended up as a WiFi discussion.

Here:
Zigbee Tradfri control almost anything - which doesn’t use the same hardware as I’m using

and I’ve tried using this:


however, using that I can’t get anything to appear on the console of the coordinator XBee so i’m doing it wrong I guess.

Current Arduino code is this: (I know it’s probably horrifically inefficient and messy, sorry)

/********************************************************************/
//libraries
#include <OneWire.h> 
#include <DallasTemperature.h>
#include <XBee.h>
#include <SoftwareSerial.h>
/********************************************************************/
// DS18B20 Setup
#define ONE_WIRE_BUS 3 
OneWire oneWire(ONE_WIRE_BUS); 
DallasTemperature sensors(&oneWire);// Pass our oneWire reference to Dallas Temperature. 
/********************************************************************/
// constants
const int pwrButtonPin = 6;     // the number of the power button pin
const int oscButtonPin = 7;     // the number of the oscillation button
const int offPin =  13;      // Power off LED pin
const int pw1Pin =  12;      // Level 1 SSD/LED pin
const int pw2Pin =  11;      // Level 2 SSD/LED pin
const int pw3Pin =  10;      // Level 3 SSD/LED pin
const int oscPin =  9;      //  Oscillation SSD/LED pin
/********************************************************************/
// variables
int cycles = 0;
int pwrButtonState = 0;
int oscButtonState = 0;
int powerLevel = 0;
int osc = 0;
/********************************************************************/
//XBee Stuff
/*
This example is for Series 2 XBee
Receives a ZB RX packet and prints the packet to softserial
*/
XBee xbee = XBee();
XBeeResponse response = XBeeResponse();

// create reusable response objects for responses we expect to handle 
ZBRxResponse rx = ZBRxResponse();
ModemStatusResponse msr = ModemStatusResponse();

// Define NewSoftSerial TX/RX pins
// Connect Arduino pin 8 to TX of usb-serial device
uint8_t ssRX = 8;
// Connect Arduino pin 4 to RX of usb-serial device
uint8_t ssTX = 4;

// Remember to connect all devices to a common Ground: XBee, Arduino and USB-Serial device
SoftwareSerial nss(ssRX, ssTX);
//End Xbee Stuff

//Setup
void setup() 
{
  // initialize the LED/SSR pins as an output:
  pinMode(offPin, OUTPUT);
  pinMode(pw1Pin, OUTPUT);
  pinMode(pw2Pin, OUTPUT);
  pinMode(pw3Pin, OUTPUT);
  pinMode(oscPin, OUTPUT);
  // initialize the pushbutton pins as an input:
  //to do: add timer button.
  pinMode(pwrButtonPin, INPUT_PULLUP);
  pinMode (oscButtonPin, INPUT_PULLUP);
  //
  // start serial port 
  Serial.begin(9600); 
  Serial.println("Starting..."); 
  // Start DS1820B 
  sensors.begin(); 
  readTemperature();
  //set power to off
  digitalWrite(offPin, HIGH);
  digitalWrite(pw1Pin, LOW);
  digitalWrite(pw2Pin, LOW);
  digitalWrite(pw3Pin, LOW);
  //set oscillation off
  digitalWrite(oscPin, LOW);
  //
  //Xbee Setup
  xbee.setSerial(Serial);
  nss.begin(9600);
  //this does not print to the console of the recieving XBee
  nss.println("Starting up!");
  //
} 
/********************************************************************/
//Loop
void loop() 
{ 
  /*******************************************************************
  //XBEE.... Commented out because it doesn't do anything.
  //this was copy/pasted from the link provided above.
  xbee.readPacket();
    
    if (xbee.getResponse().isAvailable()) {
      // got something
           
      if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE) {
        // got a zb rx packet
        
        // now fill our zb rx class
        xbee.getResponse().getZBRxResponse(rx);
      
        nss.println("Got an rx packet!");
            
        if (rx.getOption() == ZB_PACKET_ACKNOWLEDGED) {
            // the sender got an ACK
            nss.println("packet acknowledged");
        } else {
          nss.println("packet not acknowledged");
        }
        
        nss.print("checksum is ");
        nss.println(rx.getChecksum(), HEX);

        nss.print("packet length is ");
        nss.println(rx.getPacketLength(), DEC);
        
         for (int i = 0; i < rx.getDataLength(); i++) {
          nss.print("payload [");
          nss.print(i, DEC);
          nss.print("] is ");
          nss.println(rx.getData()[i], HEX);
        }
        
       for (int i = 0; i < xbee.getResponse().getFrameDataLength(); i++) {
        nss.print("frame data [");
        nss.print(i, DEC);
        nss.print("] is ");
        nss.println(xbee.getResponse().getFrameData()[i], HEX);
      }
      }
    } else if (xbee.getResponse().isError()) {
      nss.print("error code:");
      nss.println(xbee.getResponse().getErrorCode());
    }
  // End XBee stuff
  *******************************************************************/
  
  // read the state of the power button value:
  pwrButtonState = digitalRead(pwrButtonPin);
  // check if the pushbutton is pressed. If it is, the buttonState is LOW:
  if (pwrButtonState == LOW) {
    // run powerbutton:
    powerButton();
  }

  /********************************************************************/

  // read the state of the oscillate button:
  oscButtonState = digitalRead(oscButtonPin);
  // check if the button is pressed. If it is, the buttonState is LOW:
  if (oscButtonState == LOW) {
    // osc button:
    oscButton();
  }
  
  /********************************************************************/

  //Read temperature:
  if (cycles == 500) {
    cycles = 0;
    readTemperature();
  }
  
  //increment cycle count
  cycles = (cycles+1);
  delay(100); 
}
/********************************************************************/
//Power Button press
void powerButton()
{
  if (powerLevel == 0)
  {
    //set level to 1, turn on level 1 relay
    powerLevel = 1;
    digitalWrite(offPin, LOW);
    digitalWrite(pw1Pin, HIGH);
    digitalWrite(pw2Pin, LOW);
    digitalWrite(pw3Pin, LOW);
    Serial.println("Power Level 1");
  }
  else if (powerLevel == 1)
  {
    //
    powerLevel = 2;
    digitalWrite(offPin, LOW);
    digitalWrite(pw1Pin, HIGH);
    digitalWrite(pw2Pin, HIGH);
    digitalWrite(pw3Pin, LOW);
    Serial.println("Power Level 2");
  }
  else if (powerLevel == 2)
  {
    //
    powerLevel = 3;
    digitalWrite(offPin, LOW);
    digitalWrite(pw1Pin, HIGH);
    digitalWrite(pw2Pin, HIGH);
    digitalWrite(pw3Pin, HIGH);
    Serial.println("Power Level 3");
  }
  else if (powerLevel == 3)
  {
    //
    powerLevel = 0;
    digitalWrite(offPin, HIGH);
    digitalWrite(pw1Pin, LOW);
    digitalWrite(pw2Pin, LOW);
    digitalWrite(pw3Pin, LOW);
    Serial.println("Power Off");
  }
  else
  {
    powerLevel = 0;
    Serial.println("Power Level Error. Set to off"); 
    digitalWrite(offPin, HIGH);
    digitalWrite(pw1Pin, LOW);
    digitalWrite(pw2Pin, LOW);
    digitalWrite(pw3Pin, LOW);	
  }
  delay(100);
}
/********************************************************************/
//oscillate button press
void oscButton ()
{
  //if off, switch on
  if (osc == 0)
  {
    //set level to 1, turn on level 1 relay
    osc = 1;
    digitalWrite(oscPin, HIGH);
    Serial.println("oscillation on");
  }
  
  //if on, switch off
  else if (osc == 1)
  {
    //
    osc = 0;
    digitalWrite(oscPin, LOW);
    Serial.println("oscillation off");
  }
  
  //unexpected state correction. set to 0 if not 0 or 1
  else 
  {
    //
    osc = 0;
	digitalWrite(oscPin, LOW);
    Serial.println("oscillation setting error");
  }
  
  delay (100);
}
/********************************************************************/
void timerButton()
{
  //To Do...
}
/********************************************************************/
void readTemperature()
{
  sensors.requestTemperatures(); // Send the command to get temperature readings
  //print results to serial
  Serial.println("Temperature is: "); 
  Serial.println(sensors.getTempCByIndex(0)); // 0=first sensor on 1wire bus
}

So, I’d very much appreciate any pointers at all for doing the following:

  • Connecting this device to HA using ZHA
  • Control of the 3 relays via ZHA to control the power level of the fan.
  • Control the fan oscillation, via ZHA
  • Use the DS18B20 as a temperature sensor via ZHA

Thanks

1 Like

How about this? https://gio-dot.github.io/Z1-Mini/

That does look like it would do what I want. I was hoping to use the hardware I already have though. I know it’s capable, I just don’t know how to do it.

I have done a few devices using an xbee and arduino. This is an example of one project https://github.com/prairiesnpr/QuadGarageDoorController

It’s pretty rough, but I don’t have any issues with it other than some strange temp readings every so often, might give you some ideas.

1 Like

Nice, thank you. I’ll have a play with that and see if i can get anywhere.