Added sending MQTT commands to a remote control attached to GPIO pins.
This commit is contained in:
1 parent
8bc0c4a81c
commit
a34b9ba933
4 files changed
+768
No files matched your search
@@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
FanRemoteGPIO - Arduino libary to control a fan remote connected via GPIO pins.
|
||||||
|
Copyright (c) 2017 Ricky Brent
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
- Ricky Brent
|
||||||
|
|
||||||
|
Project home: https://github.com/rickybrent/fan-remote-gpio/
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#include "FanRemoteGPIO.h"
|
||||||
|
|
||||||
|
FanRemoteGPIO::FanRemoteGPIO() {
|
||||||
|
this->lightPin = -1;
|
||||||
|
this->lightPinOff = -1;
|
||||||
|
this->fanPinFast = -1;
|
||||||
|
this->fanPinMedium = -1;
|
||||||
|
this->fanPinSlow = -1;
|
||||||
|
this->fanPinOff = -1;
|
||||||
|
this->nFanSpeed = 0;
|
||||||
|
this->nBrightness = 0;
|
||||||
|
this->nMaxBrightness = 3;
|
||||||
|
this->bLightOn = false;
|
||||||
|
this->bFanOn = false;
|
||||||
|
this->looping = false;
|
||||||
|
this->heldPin = -1;
|
||||||
|
this->heldUntil = 0;
|
||||||
|
this->queue = Queue<QueuedPress>(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable a single light button and assign the pin.
|
||||||
|
*
|
||||||
|
* @param pin Arduino Pin to which the ligh button is connected to
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::enableLight(int pin) {
|
||||||
|
this->lightPin = pin;
|
||||||
|
this->lightPinOff = -1;
|
||||||
|
initPin(this->lightPin);
|
||||||
|
// We want to have the light state in sync with what we think the state is.
|
||||||
|
// Oddly, the model tested will turn *off* with a 300-ms hold, but not on,
|
||||||
|
// which is exactly what we need(?):
|
||||||
|
// press(this->lightPin, 300);
|
||||||
|
// More testing shows the fan hates to be turned off then on again rapidly.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable controlling the light, with separate pins for on and off.
|
||||||
|
*
|
||||||
|
* @param pinOn Arduino Pin to which the light on button is connected to
|
||||||
|
* @param pinOff Arduino Pin to which the light off button is connected to
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::enableLight(int pinOn, int pinOff) {
|
||||||
|
this->lightPin = pinOn;
|
||||||
|
this->lightPinOff = pinOff;
|
||||||
|
initPin(this->lightPin);
|
||||||
|
initPin(this->lightPinOff);
|
||||||
|
// If we have an on and off button, we can guarentee the proper sync state:
|
||||||
|
this->turnLight(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable controlling the light
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::disableLight() {
|
||||||
|
this->lightPin = -1;
|
||||||
|
this->lightPinOff = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable controlling the fan speeds by separate pins per speed.
|
||||||
|
*
|
||||||
|
* @param pinFast Arduino Pin connected to the fast button
|
||||||
|
* @param pinMedium Arduino Pin connected to the medium button
|
||||||
|
* @param pinSlow Arduino Pin connected to the slow button
|
||||||
|
* @param pinOff Arduino Pin connected to the off button
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::enableFanSpeeds(int pinFast, int pinMedium, int pinSlow, int pinOff) {
|
||||||
|
this->fanPinFast = pinFast;
|
||||||
|
this->fanPinMedium = pinMedium;
|
||||||
|
this->fanPinSlow = pinSlow;
|
||||||
|
this->fanPinOff = pinOff;
|
||||||
|
initPin(this->fanPinFast);
|
||||||
|
initPin(this->fanPinMedium);
|
||||||
|
initPin(this->fanPinSlow);
|
||||||
|
initPin(this->fanPinOff);
|
||||||
|
this->turnFan(false); // Easiest way to keep the real fan speed identical.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable controlling the fan speeds
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::disableFanSpeeds() {
|
||||||
|
this->fanPinFast = -1;
|
||||||
|
this->fanPinMedium = -1;
|
||||||
|
this->fanPinSlow = -1;
|
||||||
|
this->fanPinOff = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the fan light brightness.
|
||||||
|
* Ideally, this should track the brightness level, then adjust it by timing
|
||||||
|
* how long the button is held down for. This is hard to get right.
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::setBrightness(int level) {
|
||||||
|
if (level == 0) {
|
||||||
|
this->bLightOn = false;
|
||||||
|
if (this->lightPinOff < 0) {
|
||||||
|
press(this->lightPin);
|
||||||
|
} else {
|
||||||
|
press(this->lightPinOff);
|
||||||
|
}
|
||||||
|
} else if (level > 0) {
|
||||||
|
this->bLightOn = true;
|
||||||
|
// So much potential to mess up.
|
||||||
|
//int holdTime = 0;
|
||||||
|
if (this->nBrightness < this->nMaxBrightness) {
|
||||||
|
//seconds tested holding down: 1600, 1800, 2000, 2200, 2400
|
||||||
|
//this->nBrightness
|
||||||
|
}
|
||||||
|
this->nBrightness = level;
|
||||||
|
press(this->lightPin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Power the light back on without attempting to change its brightness level.
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::turnLight(bool on) {
|
||||||
|
if (!on) {
|
||||||
|
Serial.println("Turned light off");
|
||||||
|
setBrightness(0);
|
||||||
|
} else {
|
||||||
|
Serial.println("Turned light on");
|
||||||
|
//setBrightness(this->nBrightness > 0 ? this->nBrightness : this->nMaxBrightness);
|
||||||
|
// Hack because I am having a lot of trouble with the light:
|
||||||
|
this->nBrightness = this->nMaxBrightness;
|
||||||
|
this->bLightOn = true;
|
||||||
|
press(this->lightPin, 200);
|
||||||
|
//press(this->lightPin, 2400);
|
||||||
|
//press(this->lightPin, 2400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the fan light brightness.
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::setSpeed(int speed) {
|
||||||
|
if (speed == 0) {
|
||||||
|
this->bFanOn = false;
|
||||||
|
press(this->fanPinOff);
|
||||||
|
} else {
|
||||||
|
this->bFanOn = true;
|
||||||
|
this->nFanSpeed = speed;
|
||||||
|
if (speed == 1) {
|
||||||
|
press(this->fanPinSlow);
|
||||||
|
} else if (speed == 2) {
|
||||||
|
press(this->fanPinMedium);
|
||||||
|
} else if (speed == 3) {
|
||||||
|
press(this->fanPinFast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Power the fan back on to its last set speed.
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::turnFan(bool on) {
|
||||||
|
if (!on) {
|
||||||
|
setSpeed(0);
|
||||||
|
} else {
|
||||||
|
setSpeed(this->nFanSpeed > 0 ? this->nFanSpeed : 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release any buttons being held down long enough.
|
||||||
|
*/
|
||||||
|
bool FanRemoteGPIO::available() {
|
||||||
|
this->looping = true;
|
||||||
|
if (this->heldPin >= 0 && this->heldUntil != 0 && this->heldUntil <= millis()) {
|
||||||
|
Serial.println("timed release!");
|
||||||
|
digitalWrite(this->heldPin, HIGH);
|
||||||
|
this->heldPin = -1;
|
||||||
|
if ((queue.count()) > 0) {
|
||||||
|
QueuedPress queued = queue.pop();
|
||||||
|
Serial.println("Queue in use");
|
||||||
|
press(queued.pin, queued.time);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FanRemoteGPIO::getBrightness() {
|
||||||
|
return ((this->bLightOn) ? this->nBrightness : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FanRemoteGPIO::getSpeed() {
|
||||||
|
return ((this->bFanOn) ? this->nFanSpeed : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FanRemoteGPIO::isLightOn() {
|
||||||
|
return this->bLightOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FanRemoteGPIO::isFanOn() {
|
||||||
|
return this->bFanOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set pin to output and HIGH.
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::initPin(int pin) {
|
||||||
|
pinMode(pin, OUTPUT);
|
||||||
|
digitalWrite(pin, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hold down the light button for the given ms. Useful for testing.
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::holdLightButton(int time) {
|
||||||
|
press(this->lightPin, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Press a button.
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::press(int pin) {
|
||||||
|
press(pin, 200); // Too long, and the light will begin adjusting brightness.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Press a button, hold for the specified time, then release.
|
||||||
|
* @param pin Pin to press.
|
||||||
|
* @param time Delay before releasing, in milliseconds.
|
||||||
|
*/
|
||||||
|
void FanRemoteGPIO::press(int pin, int time) {
|
||||||
|
Serial.print("Pressed");
|
||||||
|
Serial.println(pin);
|
||||||
|
if (pin < 0)
|
||||||
|
return;
|
||||||
|
if (this->heldPin > -1) {
|
||||||
|
struct QueuedPress queued;
|
||||||
|
queued.pin = pin;
|
||||||
|
queued.time = time;
|
||||||
|
this->queue.push(queued);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
digitalWrite(pin, LOW);
|
||||||
|
if (this->looping) {
|
||||||
|
this->heldPin = pin;
|
||||||
|
this->heldUntil = millis() + time;
|
||||||
|
} else {
|
||||||
|
if (time > 0) delay(time);
|
||||||
|
Serial.print("Released");
|
||||||
|
Serial.println(pin);
|
||||||
|
digitalWrite(pin, HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
FanRemoteGPIO - Arduino libary to control a fan remote connected via GPIO pins.
|
||||||
|
Copyright (c) 2017 Ricky Brent
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
- Ricky Brent
|
||||||
|
|
||||||
|
Project home: https://github.com/rickybrent/fan-remote-gpio/
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef FanRemoteGPIO_h
|
||||||
|
#define FanRemoteGPIO_h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "Queue.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
class FanRemoteGPIO
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FanRemoteGPIO();
|
||||||
|
void enableLight(int pin);
|
||||||
|
void enableLight(int pinOn, int pinOff);
|
||||||
|
void enableFanSpeeds(int pinFast, int pinMedium, int pinSlow, int pinOff);
|
||||||
|
void disableLight();
|
||||||
|
void disableFanSpeeds();
|
||||||
|
void turnLight(bool on);
|
||||||
|
void setBrightness(int brightness);
|
||||||
|
void turnFan(bool on);
|
||||||
|
void setSpeed(int speed);
|
||||||
|
void holdLightButton(int time);
|
||||||
|
int getBrightness();
|
||||||
|
int getSpeed();
|
||||||
|
bool isLightOn();
|
||||||
|
bool isFanOn();
|
||||||
|
bool available();
|
||||||
|
private:
|
||||||
|
void initPin(int pin);
|
||||||
|
void press(int pin);
|
||||||
|
void press(int pin, int time);
|
||||||
|
int lightPin;
|
||||||
|
int lightPinOff;
|
||||||
|
int fanPinFast;
|
||||||
|
int fanPinMedium;
|
||||||
|
int fanPinSlow;
|
||||||
|
int fanPinOff;
|
||||||
|
int heldPin;
|
||||||
|
unsigned long heldUntil;
|
||||||
|
bool looping;
|
||||||
|
bool bLightOn;
|
||||||
|
bool bFanOn;
|
||||||
|
uint8_t nBrightness;
|
||||||
|
uint8_t nMaxBrightness;
|
||||||
|
uint8_t nFanSpeed;
|
||||||
|
struct QueuedPress {
|
||||||
|
int pin;
|
||||||
|
int time;
|
||||||
|
};
|
||||||
|
Queue<QueuedPress> queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -4,8 +4,16 @@ Tutorial and schema are there https://1technophile.blogspot.com/2016/09/433tomqt
|
|||||||
433nIRtoMQTTto433nIR - ESP8266 gateway between 433mhz, infrared and MQTT on both directions
|
433nIRtoMQTTto433nIR - ESP8266 gateway between 433mhz, infrared and MQTT on both directions
|
||||||
Tutorial and schema are there https://1technophile.blogspot.fr/2016/11/433nIRtomqttto433nIR-bidirectional-esp8266.html
|
Tutorial and schema are there https://1technophile.blogspot.fr/2016/11/433nIRtomqttto433nIR-bidirectional-esp8266.html
|
||||||
|
|
||||||
|
433toMQTTto433nFan_ESP8266 - ESP8266 gateway between 433mhz and a fan's remote control, from MQTT to the fan only.
|
||||||
|
Tutorial is here https://github.com/rickybrent/433toMQTTto433_ESP8266/wiki/Flower-Angel-18R-ST6
|
||||||
|
|
||||||
These gateways can be integrated with home automation systems like Openhab or Home assistant thanks to the MQTT protocol.
|
These gateways can be integrated with home automation systems like Openhab or Home assistant thanks to the MQTT protocol.
|
||||||
|
|
||||||
|
A list of supported 433mhz devices is available here:
|
||||||
|
https://community.home-assistant.io/t/433tomqttto433-gateway-device-list/7819
|
||||||
|
|
||||||
|
The gateway integrate Ntuple 433mhz signal detection over a determined time to avoid unnecessary MQTT messages.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
and associated documentation files (the "Software"), to deal in the Software without restriction,
|
and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
|||||||
@@ -0,0 +1,406 @@
|
|||||||
|
/*
|
||||||
|
433nIRtoMQTTto433nIR - ESP8266 program for home automation
|
||||||
|
Tested OK on GeekCreek ESP12F
|
||||||
|
Fan remote control tested OK on Wemos D1 Mini
|
||||||
|
Not working on NodeMCU V0.9
|
||||||
|
Act as a wifi gateway between your 433mhz/infrared IR signal and a MQTT broker
|
||||||
|
Send and receiving command by MQTT
|
||||||
|
|
||||||
|
This program enables to:
|
||||||
|
- receive MQTT data from a topic and send RF 433Mhz signal corresponding to the received MQTT data
|
||||||
|
- publish MQTT data to a different topic related to received 433Mhz signal
|
||||||
|
- receive MQTT data from a topic and send IR signal corresponding to the received MQTT data
|
||||||
|
- publish MQTT data to a different topic related to received IR signal
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
- 1technophile
|
||||||
|
- crankyoldgit
|
||||||
|
- rickybrent
|
||||||
|
Based on:
|
||||||
|
- MQTT library (https://github.com/knolleary)
|
||||||
|
- RCSwitch (https://github.com/sui77/rc-switch)
|
||||||
|
- ESP8266Wifi
|
||||||
|
- IRremoteESP8266 (https://github.com/markszabo/IRremoteESP8266)
|
||||||
|
|
||||||
|
Project home: https://github.com/1technophile/433nIRtoMQTTto433nIR_ESP8266
|
||||||
|
Blog, tutorial: http://1technophile.blogspot.com/2016/09/433nIRtomqttto433nIR-bidirectional-esp8266.html
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
|
and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
|
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
Some usefull commands to test gateway with mosquitto:
|
||||||
|
Subscribe to the subject for data receiption from RF signal
|
||||||
|
mosquitto_sub -t home/433toMQTT
|
||||||
|
Send data by MQTT to convert it on RF signal
|
||||||
|
mosquitto_pub -t home/MQTTto433/ -m 1315153
|
||||||
|
*/
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <PubSubClient.h>
|
||||||
|
#include <RCSwitch.h> // library for controling Radio frequency switch
|
||||||
|
#include <IRremoteESP8266.h>
|
||||||
|
#include <FanRemoteGPIO.h> // library for controlling a fan remote via GPIO pins
|
||||||
|
#include <pins_arduino.h>
|
||||||
|
|
||||||
|
RCSwitch mySwitch = RCSwitch();
|
||||||
|
FanRemoteGPIO fanRemote = FanRemoteGPIO();
|
||||||
|
|
||||||
|
//TODO: Disabled IR] IRrecv irrecv(D3); // Untested. Moved from 2.
|
||||||
|
//TODO: Disabled IR] IRsend irsend(D4); // Untested. Moved from 14.
|
||||||
|
|
||||||
|
decode_results results;
|
||||||
|
|
||||||
|
//Do we want to see trace for debugging purposes
|
||||||
|
#define TRACE 1 // 0= trace off 1 = trace on
|
||||||
|
|
||||||
|
// Update these with values suitable for your network.
|
||||||
|
#define wifi_ssid "mywifiid"
|
||||||
|
#define wifi_password "mypwd"
|
||||||
|
#define mqtt_server "192.168.0.22"
|
||||||
|
#define mqtt_user "your_username" // not compulsory if you set it uncomment line 143 and comment line 145
|
||||||
|
#define mqtt_password "your_password" // not compulsory if you set it uncomment line 143 and comment line 145
|
||||||
|
|
||||||
|
//variables to avoid duplicates for RF
|
||||||
|
#define time_avoid_duplicate 3000 // if you want to avoid duplicate mqtt message received set this to > 0, the value is the time in milliseconds during which we don't publish duplicates
|
||||||
|
// array to store previous received RFs codes and their timestamps
|
||||||
|
long ReceivedRF[10][2] ={{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}};
|
||||||
|
|
||||||
|
#define subjectMQTTtoX "home/commands/#"
|
||||||
|
//RF MQTT Subjects
|
||||||
|
#define subject433toMQTT "home/433toMQTT"
|
||||||
|
#define subjectMQTTto433 "home/commands/MQTTto433"
|
||||||
|
//IR MQTT Subjects
|
||||||
|
/*TODO: Disabled IR]
|
||||||
|
#define subjectIRtoMQTT "home/sensors/ir"
|
||||||
|
#define subjectMQTTtoIRCOOLIX "home/commands/sendCOOLIX"
|
||||||
|
#define subjectMQTTtoIRWhynter "home/commands/sendWhynter"
|
||||||
|
#define subjectMQTTtoIRNEC "home/commands/sendNEC"
|
||||||
|
#define subjectMQTTtoIRLG "home/commands/sendLG"
|
||||||
|
#define subjectMQTTtoIRSony "home/commands/sendSony"
|
||||||
|
#define subjectMQTTtoIRDISH "home/commands/sendDISH"
|
||||||
|
#define subjectMQTTtoIRSharp "home/commands/sendSharp"
|
||||||
|
#define subjectMQTTtoIRPanasonic "home/commands/sendPanasonic"
|
||||||
|
#define subjectMQTTtoIRSAMSUNG "home/commands/sendSAMSUNG"
|
||||||
|
TODO: Disabled IR] */
|
||||||
|
//Fan MQTT Subjects
|
||||||
|
#define subjectMQTTtoFanSpeed "home/commands/MQTTtoFan/speed" // 0 to 3
|
||||||
|
#define subjectMQTTtoFanBrightness "home/commands/MQTTtoFan/brightness" // 0 to 3
|
||||||
|
#define subjectMQTTtoFanLight "home/commands/MQTTtoFan/light" // ON or OFF
|
||||||
|
#define subjectMQTTtoFan "home/commands/MQTTtoFan/fan" // ON or OFF
|
||||||
|
#define subjectMQTTtoFanHoldLight "home/commands/MQTTtoFan/holdLight"
|
||||||
|
#define subjectFanToMQTT "home/FanToMQTT"
|
||||||
|
|
||||||
|
//adding this to bypass to problem of the arduino builder issue 50
|
||||||
|
void callback(char*topic, byte* payload,unsigned int length);
|
||||||
|
WiFiClient espClient;
|
||||||
|
|
||||||
|
// client parameters
|
||||||
|
PubSubClient client(mqtt_server, 1883, callback, espClient);
|
||||||
|
|
||||||
|
//MQTT last attemps reconnection number
|
||||||
|
long lastReconnectAttempt = 0;
|
||||||
|
|
||||||
|
// Callback function, when the gateway receive an MQTT value on the topics subscribed this function is called
|
||||||
|
void callback(char* topic, byte* payload, unsigned int length) {
|
||||||
|
// In order to republish this payload, a copy must be made
|
||||||
|
// as the orignal payload buffer will be overwritten whilst
|
||||||
|
// constructing the PUBLISH packet.
|
||||||
|
trc("Hey I got a callback ");
|
||||||
|
// Allocate the correct amount of memory for the payload copy
|
||||||
|
byte* p = (byte*)malloc(length + 1);
|
||||||
|
// Copy the payload to the new buffer
|
||||||
|
memcpy(p,payload,length);
|
||||||
|
|
||||||
|
// Conversion to a printable string
|
||||||
|
p[length] = '\0';
|
||||||
|
String callbackstring = String((char *) p);
|
||||||
|
String topicNameRec = String((char*) topic);
|
||||||
|
|
||||||
|
//launch the function to treat received data
|
||||||
|
receivingMQTT(topicNameRec,callbackstring);
|
||||||
|
|
||||||
|
// Free the memory
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
//Launch serial for debugging purposes
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
//Begining wifi connection
|
||||||
|
setup_wifi();
|
||||||
|
delay(1500);
|
||||||
|
|
||||||
|
lastReconnectAttempt = 0;
|
||||||
|
|
||||||
|
//IR init parameters
|
||||||
|
//TODO: Disabled IR] irsend.begin();
|
||||||
|
//TODO: Disabled IR] irrecv.enableIRIn(); // Start the receiver
|
||||||
|
|
||||||
|
//RF init parameters
|
||||||
|
mySwitch.enableTransmit(D2); // RF Transmitter is connected to Pin D2
|
||||||
|
mySwitch.setRepeatTransmit(20); //increase transmit repeat to avoid lost of rf sendings
|
||||||
|
mySwitch.enableReceive(D1); // Receiver on pin D1
|
||||||
|
|
||||||
|
//FanRemote init parameters.
|
||||||
|
fanRemote.enableFanSpeeds(D0, D5, D6, D7);
|
||||||
|
fanRemote.enableLight(D4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_wifi() {
|
||||||
|
delay(10);
|
||||||
|
// We start by connecting to a WiFi network
|
||||||
|
trc("Connecting to ");
|
||||||
|
trc(wifi_ssid);
|
||||||
|
|
||||||
|
WiFi.begin(wifi_ssid, wifi_password);
|
||||||
|
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
trc(".");
|
||||||
|
}
|
||||||
|
trc("WiFi connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean reconnect() {
|
||||||
|
// Loop until we're reconnected
|
||||||
|
while (!client.connected()) {
|
||||||
|
trc("Attempting MQTT connection...");
|
||||||
|
// Attempt to connect
|
||||||
|
// If you want to use a username and password, uncomment next line and comment the line if (client.connect("433toMQTTto433")) {
|
||||||
|
//if (client.connect("433nIRtoMQTTto433nIR", mqtt_user, mqtt_password)) {
|
||||||
|
// and set username and password at the program beginning
|
||||||
|
if (client.connect("433nIRtoMQTTto433nIR")) {
|
||||||
|
// Once connected, publish an announcement...
|
||||||
|
client.publish("outTopic","hello world");
|
||||||
|
publishFanState();
|
||||||
|
trc("connected");
|
||||||
|
//Subscribing to topic(s)
|
||||||
|
subscribing(subjectMQTTtoX);
|
||||||
|
} else {
|
||||||
|
trc("failed, rc=");
|
||||||
|
trc(String(client.state()));
|
||||||
|
trc(" try again in 5 seconds");
|
||||||
|
// Wait 5 seconds before retrying
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return client.connected();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
//MQTT client connexion management
|
||||||
|
if (!client.connected()) {
|
||||||
|
long now = millis();
|
||||||
|
if (now - lastReconnectAttempt > 5000) {
|
||||||
|
lastReconnectAttempt = now;
|
||||||
|
trc("client mqtt not connected, trying to connect");
|
||||||
|
// Attempt to reconnect
|
||||||
|
if (reconnect()) {
|
||||||
|
lastReconnectAttempt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// MQTT loop
|
||||||
|
client.loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive loop, if data received by RF433 send it by MQTT to subject433toMQTT
|
||||||
|
if (mySwitch.available()) {
|
||||||
|
// Topic on which we will send data
|
||||||
|
trc("Receiving 433Mhz signal");
|
||||||
|
unsigned long MQTTvalue;
|
||||||
|
MQTTvalue=mySwitch.getReceivedValue();
|
||||||
|
mySwitch.resetAvailable();
|
||||||
|
if (client.connected()) {
|
||||||
|
if (!isAduplicate(MQTTvalue)) {// conditions to avoid duplications of RF -->MQTT
|
||||||
|
trc("Sending 433Mhz signal to MQTT");
|
||||||
|
trc(String(MQTTvalue));
|
||||||
|
sendMQTT(subject433toMQTT,String(MQTTvalue));
|
||||||
|
storeValue(MQTTvalue);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (reconnect()) {
|
||||||
|
trc("Sending 433Mhz signal to MQTT after reconnect");
|
||||||
|
trc(String(MQTTvalue));
|
||||||
|
sendMQTT(subject433toMQTT,String(MQTTvalue));
|
||||||
|
storeValue(MQTTvalue);
|
||||||
|
lastReconnectAttempt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive loop, if data received by IR send it by MQTT to subjectIRtoMQTT
|
||||||
|
/*TODO: Disabled IR]
|
||||||
|
if (irrecv.decode(&results)) {
|
||||||
|
trc("Receiving IR signal");
|
||||||
|
String MQTTvalue;
|
||||||
|
MQTTvalue=results.value;
|
||||||
|
trc("Sending IR signal to MQTT");
|
||||||
|
trc(MQTTvalue);
|
||||||
|
sendMQTT(subjectIRtoMQTT,MQTTvalue);
|
||||||
|
irrecv.resume(); // Receive the next value
|
||||||
|
}
|
||||||
|
TODO: Disabled IR] */
|
||||||
|
|
||||||
|
// Receive loop, check for data from fan remote and release held buttons.
|
||||||
|
if (fanRemote.available()) {
|
||||||
|
publishFanState();
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(100);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void storeValue(long MQTTvalue){
|
||||||
|
long now = millis();
|
||||||
|
// find oldest value of the buffer
|
||||||
|
int o = getMin();
|
||||||
|
trc("Minimum index: " + String(o));
|
||||||
|
// replace it by the new one
|
||||||
|
ReceivedRF[o][0] = MQTTvalue;
|
||||||
|
ReceivedRF[o][1] = now;
|
||||||
|
trc("send this code :" + String(ReceivedRF[o][0])+"/"+String(ReceivedRF[o][1]));
|
||||||
|
trc("Col: value/timestamp");
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
trc(String(i) + ":" + String(ReceivedRF[i][0])+"/"+String(ReceivedRF[i][1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMin(){
|
||||||
|
int minimum = ReceivedRF[0][1];
|
||||||
|
int minindex=0;
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
if (ReceivedRF[i][1] < minimum) {
|
||||||
|
minimum = ReceivedRF[i][1];
|
||||||
|
minindex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minindex;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isAduplicate(long value){
|
||||||
|
trc("isAduplicate");
|
||||||
|
// check if the value has been already sent during the last "time_avoid_duplicate"
|
||||||
|
for (int i=0; i<10;i++){
|
||||||
|
if (ReceivedRF[i][0] == value){
|
||||||
|
long now = millis();
|
||||||
|
if (now - ReceivedRF[i][1] < time_avoid_duplicate){
|
||||||
|
trc("don't send this code :" + String(ReceivedRF[i][0])+"/"+String(ReceivedRF[i][1]));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subscribing(String topicNameRec){ // MQTT subscribing to topic
|
||||||
|
char topicStrRec[26];
|
||||||
|
topicNameRec.toCharArray(topicStrRec,26);
|
||||||
|
// subscription to topic for receiving data
|
||||||
|
boolean pubresult = client.subscribe(topicStrRec);
|
||||||
|
if (pubresult) {
|
||||||
|
trc("subscription OK to");
|
||||||
|
trc(topicNameRec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void receivingMQTT(String topicNameRec, String callbackstring) {
|
||||||
|
trc("Receiving data by MQTT");
|
||||||
|
trc(topicNameRec);
|
||||||
|
char topicOri[26] = "";
|
||||||
|
char topicStrAck[26] = "";
|
||||||
|
char datacallback[32] = "";
|
||||||
|
// Acknowledgement inside a subtopic to avoid loop
|
||||||
|
topicNameRec.toCharArray(topicOri,26);
|
||||||
|
char DataAck[26] = "OK";
|
||||||
|
client.publish("home/ack", DataAck);
|
||||||
|
callbackstring.toCharArray(datacallback,32);
|
||||||
|
trc(datacallback);
|
||||||
|
unsigned long data = strtoul(datacallback, NULL, 10); // we will not be able to pass value > 4294967295
|
||||||
|
trc(String(data));
|
||||||
|
|
||||||
|
if (topicNameRec == subjectMQTTto433){
|
||||||
|
trc("Send received data by RF 433");
|
||||||
|
//send received MQTT value by RF signal (example of signal sent data = 5264660)
|
||||||
|
mySwitch.send(data, 24);
|
||||||
|
}
|
||||||
|
/*TODO: Disabled IR]
|
||||||
|
//send received MQTT value by IR signal (example of signal sent data = 1086296175)
|
||||||
|
if (topicNameRec == subjectMQTTtoIRCOOLIX)
|
||||||
|
irsend.sendCOOLIX(data, 24);
|
||||||
|
if (topicNameRec == subjectMQTTtoIRWhynter)
|
||||||
|
irsend.sendWhynter(data, 32);
|
||||||
|
if (topicNameRec == subjectMQTTtoIRNEC)
|
||||||
|
irsend.sendNEC(data, 32);
|
||||||
|
if (topicNameRec == subjectMQTTtoIRLG)
|
||||||
|
irsend.sendLG(data, 28);
|
||||||
|
if (topicNameRec == subjectMQTTtoIRSony)
|
||||||
|
irsend.sendSony(data, 12);
|
||||||
|
if (topicNameRec == subjectMQTTtoIRDISH)
|
||||||
|
irsend.sendDISH(data, 16);
|
||||||
|
if (topicNameRec == subjectMQTTtoIRSharp)
|
||||||
|
irsend.sendSharpRaw(data, 15);
|
||||||
|
Panasonic has a two arguments per call. An address(16bit) and data(32bit), not data and nr_bits.
|
||||||
|
if (topicNameRec == subjectMQTTtoIRPanasonic)
|
||||||
|
irsend.sendPanasonic(data, 36);
|
||||||
|
if (topicNameRec == subjectMQTTtoIRSAMSUNG)
|
||||||
|
irsend.sendSAMSUNG(data, 32);
|
||||||
|
TODO: Disabled IR] */
|
||||||
|
//control attached fan remote control based on recieved MQTT values
|
||||||
|
if (topicNameRec == subjectMQTTtoFanBrightness)
|
||||||
|
fanRemote.setBrightness(data);
|
||||||
|
if (topicNameRec == subjectMQTTtoFanLight)
|
||||||
|
fanRemote.turnLight(((callbackstring == "ON") || data > 0) ? true : false);
|
||||||
|
if (topicNameRec == subjectMQTTtoFan)
|
||||||
|
fanRemote.turnFan(((callbackstring == "ON") || data > 0) ? true : false);
|
||||||
|
if (topicNameRec == subjectMQTTtoFanSpeed)
|
||||||
|
fanRemote.setSpeed(data);
|
||||||
|
if (topicNameRec == subjectMQTTtoFanHoldLight)
|
||||||
|
fanRemote.holdLightButton(data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//send MQTT data dataStr to topic topicNameSend
|
||||||
|
void sendMQTT(String topicNameSend, String dataStr){
|
||||||
|
|
||||||
|
char topicStrSend[26];
|
||||||
|
topicNameSend.toCharArray(topicStrSend,26);
|
||||||
|
char dataStrSend[200];
|
||||||
|
dataStr.toCharArray(dataStrSend,200);
|
||||||
|
boolean pubresult = client.publish(topicStrSend,dataStrSend);
|
||||||
|
trc("sending ");
|
||||||
|
trc(dataStr);
|
||||||
|
trc("to ");
|
||||||
|
trc(topicNameSend);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// function called to publish the state of the fan
|
||||||
|
void publishFanState() {
|
||||||
|
String json = String("{\"brightness\":") + fanRemote.getBrightness() + ","
|
||||||
|
" \"speed\":" + fanRemote.getSpeed() + ","
|
||||||
|
" \"light\":\"" + (fanRemote.isLightOn() ? "ON" : "OFF") + "\","
|
||||||
|
" \"fan\":\"" + (fanRemote.isFanOn() ? "ON" : "OFF") + "\""
|
||||||
|
"}";
|
||||||
|
const char * msg = json.c_str();
|
||||||
|
client.publish(subjectFanToMQTT, msg, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//trace
|
||||||
|
void trc(String msg){
|
||||||
|
if (TRACE) {
|
||||||
|
Serial.println(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user