Merge branch 'arendst/development' into development

This commit is contained in:
reloxx13 2018-10-25 23:55:02 +02:00
commit d06c0c2636
146 changed files with 4403 additions and 1751 deletions

65
API.md Normal file
View File

@ -0,0 +1,65 @@
## Sonoff-Tasmota basic API information
Sonoff-Tasmota can easily be extended by developers using provided function pointers as callback Ids. This document lists the available callback function Ids. See the wiki (https://github.com/arendst/Sonoff-Tasmota/wiki/Sensor-API) for more information.
Callback availability can be checked by searching for either XdrvCall, XsnsCall, XdspCall and XnrgCall.
## Driver, Sensor and Energy Callback Ids
The following table lists Callback Ids and their availability for a Driver, Sensor or Energy service.
Callback Id | Bool | Version | xdrv | xsns | xnrg | Description
----------------------------|------|----------|------|------|------|----------------------------------
FUNC_SETTINGS_OVERRIDE | | 6.2.1.19 | x | | | Override start-up settings
FUNC_MODULE_INIT | x | 6.2.1.17 | x | | | Init module specific parameters
FUNC_PRE_INIT | | | x | | x | Once GPIO have been established
FUNC_INIT | | | x | x | x | At end of initialisation
FUNC_LOOP | | | x | | | In main loop
FUNC_EVERY_50_MSECOND | | | x | x | |
FUNC_EVERY_100_MSECOND | | | x | x | |
FUNC_EVERY_200_MSECOND | | | | x | x |
FUNC_EVERY_250_MSECOND | | | x | | |
FUNC_EVERY_SECOND | | | x | x | x |
FUNC_PREP_BEFORE_TELEPERIOD | | | | x | | Deprecated. Use a FUNC_EVERY_
FUNC_JSON_APPEND | | | | x | | Extend teleperiod JSON text
FUNC_WEB_APPEND | | | | x | | Extend webgui ajax info
FUNC_SAVE_BEFORE_RESTART | | | | x | | Just before a planned restart
FUNC_COMMAND | x | | x | x | | When a command is not recognized
FUNC_MQTT_SUBSCRIBE | | 5.12.0k | x | | | At end of MQTT subscriptions
FUNC_MQTT_INIT | | 5.12.0k | x | | | Once at end of MQTT connection
FUNC_MQTT_DATA | x | 5.12.0k | x | | | Before decoding command
FUNC_SET_POWER | | | x | | | Before setting relays
FUNC_SET_DEVICE_POWER | x | 6.2.1.18 | x | | | Set relay
FUNC_SHOW_SENSOR | | | x | | | When FUNC_JSON_APPEND completes
FUNC_RULES_PROCESS | x | 6.0.0 | x | | | Process specific rule
FUNC_SERIAL | x | | x | | x | Process serial data
FUNC_FREE_MEM | | | x | | | Show free memory for debugging
FUNC_BUTTON_PRESSED | x | 6.2.1.18 | x | | | When a button is pressed
FUNC_WEB_ADD_BUTTON | | 6.2.1.14 | x | x | | Add a Configuration Button to GUI
FUNC_WEB_ADD_MAIN_BUTTON | | 6.2.1.14 | x | x | | Add a main button to GUI
FUNC_WEB_ADD_HANDLER | | 6.2.1.14 | x | x | | Add a webserver handler
## Display Call back Ids
The following table lists all Callback Ids for a Display service.
Callback Id | Bool | Version | Description
------------------------------|------|----------|---------------------
FUNC_DISPLAY_INIT_DRIVER | | 6.1.1.7 |
FUNC_DISPLAY_INIT | | 6.1.1.7 |
FUNC_DISPLAY_EVERY_50_MSECOND | | 6.1.1.7 |
FUNC_DISPLAY_EVERY_SECOND | | 6.1.1.7 |
FUNC_DISPLAY_MODEL | x | 6.1.1.7 |
FUNC_DISPLAY_MODE | | 6.1.1.7 |
FUNC_DISPLAY_POWER | | 6.1.1.7 |
FUNC_DISPLAY_CLEAR | | 6.1.1.7 |
FUNC_DISPLAY_DRAW_FRAME | | 6.1.1.7 |
FUNC_DISPLAY_DRAW_HLINE | | 6.1.1.7 |
FUNC_DISPLAY_DRAW_VLINE | | 6.1.1.7 |
FUNC_DISPLAY_DRAW_LINE | | 6.1.1.7 |
FUNC_DISPLAY_DRAW_CIRCLE | | 6.1.1.7 |
FUNC_DISPLAY_FILL_CIRCLE | | 6.1.1.7 |
FUNC_DISPLAY_DRAW_RECTANGLE | | 6.1.1.7 |
FUNC_DISPLAY_FILL_RECTANGLE | | 6.1.1.7 |
FUNC_DISPLAY_TEXT_SIZE | | 6.1.1.7 |
FUNC_DISPLAY_FONT_SIZE | | 6.1.1.7 |
FUNC_DISPLAY_ROTATION | | 6.1.1.7 |
FUNC_DISPLAY_DRAW_STRING | | 6.1.1.7 |
FUNC_DISPLAY_ONOFF | | 6.1.1.7 |

View File

@ -55,7 +55,7 @@ See [Tasmota ESP/Arduino library version related issues](https://github.com/aren
| USE_SUNRISE | - | - | x | x | x |
| USE_RULES | - | - | x | x | x |
| | | | | | |
| USE_ADC_VCC | x | x | x | x | x |
| USE_ADC_VCC | x | x | x | x | |
| USE_DS18B20 | - | - | - | - | - | Single sensor
| USE_DS18x20 | - | x | x | x | x | Multiple sensors
| USE_DS18x20_LEGACY | - | - | - | - | - | Multiple sensors
@ -79,9 +79,11 @@ See [Tasmota ESP/Arduino library version related issues](https://github.com/aren
| USE_LM75AD | - | - | x | x | x |
| USE_APDS9960 | - | - | - | - | - |
| USE_MCP230xx | - | - | - | - | - |
| USE_PCA9685 | - | - | - | - | - |
| USE_MPR121 | - | - | - | - | - |
| USE_CCS811 | - | - | - | - | - |
| USE_MPU6050 | - | - | - | - | - |
| USE_DS3231 | - | - | - | - | - |
| | | | | | |
| Feature or Sensor | minimal | classic | sonoff | knx | sensors |
| USE_SPI | - | - | - | - | - |
@ -90,9 +92,13 @@ See [Tasmota ESP/Arduino library version related issues](https://github.com/aren
| USE_PMS5003 | - | - | x | x | x |
| USE_NOVA_SDS | - | - | x | x | x |
| USE_PZEM004T | - | - | x | x | x |
| USE_PZEM_AC | - | - | x | x | x |
| USE_PZEM_DC | - | - | x | x | x |
| USE_MCP39F501 | - | - | x | x | x |
| USE_SERIAL_BRIDGE | - | - | x | x | x |
| USE_SDM120 | - | - | - | - | x |
| USE_SDM630 | - | - | - | - | x |
| USE_MP3_PLAYER | - | - | - | - | - |
| USE_IR_REMOTE | - | - | x | x | x |
| USE_IR_HVAC | - | - | - | - | x |
| USE_IR_RECEIVE | - | - | x | x | x |
@ -101,7 +107,11 @@ See [Tasmota ESP/Arduino library version related issues](https://github.com/aren
| USE_ARILUX_RF | - | - | x | x | x |
| USE_SR04 | - | - | x | x | x |
| USE_TM1638 | - | - | - | - | - |
| USE_HX711 | - | - | x | x | x |
| USE_RF_FLASH | - | - | x | x | x |
| USE_TUYA_DIMMER | - | - | x | x | x |
| USE_TX20_WIND_SENSOR | - | - | x | x | x |
| USE_DISPLAY | - | - | - | - | - |
## Changelog
Version 6.2.1 20180905

View File

@ -1,37 +0,0 @@
sudo: false
language: bash
os:
- linux
script:
- /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16
- sleep 3
- export DISPLAY=:1.0
- wget http://downloads.arduino.cc/arduino-1.6.5-linux64.tar.xz
- tar xf arduino-1.6.5-linux64.tar.xz
- mv arduino-1.6.5 $HOME/arduino_ide
- export PATH="$HOME/arduino_ide:$PATH"
- which arduino
- mkdir -p $HOME/Arduino/libraries
- cp -r $TRAVIS_BUILD_DIR $HOME/Arduino/libraries/ESPAsyncUDP
- cd $HOME/arduino_ide/hardware
- mkdir esp8266com
- cd esp8266com
- git clone https://github.com/esp8266/Arduino.git esp8266
- cd esp8266/tools
- python get.py
- source $TRAVIS_BUILD_DIR/travis/common.sh
- arduino --board esp8266com:esp8266:generic --save-prefs
- arduino --get-pref sketchbook.path
- build_sketches arduino $HOME/Arduino/libraries/ESPAsyncUDP esp8266
notifications:
email:
on_success: change
on_failure: change
webhooks:
urls:
- https://webhooks.gitter.im/e/60e65d0c78ea0a920347
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false

View File

@ -1,10 +0,0 @@
# ESPAsyncUDP
Async UDP Library for ESP8266 Arduino [![Build Status](https://travis-ci.org/me-no-dev/ESPAsyncUDP.svg?branch=master)](https://travis-ci.org/me-no-dev/ESPAsyncUDP)
[![Join the chat at https://gitter.im/me-no-dev/ESPAsyncWebServer](https://badges.gitter.im/me-no-dev/ESPAsyncWebServer.svg)](https://gitter.im/me-no-dev/ESPAsyncWebServer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
This is a fully asynchronous UDP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP8266 MCUs.
The library is easy to use and includes support for Unicast, Broadcast and Multicast environments
Latest GIT version of ESP8266 Arduino might be required for this library to work

View File

@ -1,51 +0,0 @@
#include <ESP8266WiFi.h>
#include "ESPAsyncUDP.h"
const char * ssid = "***********";
const char * password = "***********";
AsyncUDP udp;
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed");
while(1) {
delay(1000);
}
}
if(udp.connect(IPAddress(192,168,1,100), 1234)) {
Serial.println("UDP connected");
udp.onPacket([](AsyncUDPPacket packet) {
Serial.print("UDP Packet Type: ");
Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast");
Serial.print(", From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.print(packet.remotePort());
Serial.print(", To: ");
Serial.print(packet.localIP());
Serial.print(":");
Serial.print(packet.localPort());
Serial.print(", Length: ");
Serial.print(packet.length());
Serial.print(", Data: ");
Serial.write(packet.data(), packet.length());
Serial.println();
//reply to the client
packet.printf("Got %u bytes of data", packet.length());
});
//Send unicast
udp.print("Hello Server!");
}
}
void loop()
{
delay(1000);
//Send broadcast on port 1234
udp.broadcastTo("Anyone here?", 1234);
}

View File

@ -1,52 +0,0 @@
#include <ESP8266WiFi.h>
#include "ESPAsyncUDP.h"
const char * ssid = "***********";
const char * password = "***********";
AsyncUDP udp;
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed");
while(1) {
delay(1000);
}
}
if(udp.listenMulticast(IPAddress(239,1,2,3), 1234)) {
Serial.print("UDP Listening on IP: ");
Serial.println(WiFi.localIP());
udp.onPacket([](AsyncUDPPacket packet) {
Serial.print("UDP Packet Type: ");
Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast");
Serial.print(", From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.print(packet.remotePort());
Serial.print(", To: ");
Serial.print(packet.localIP());
Serial.print(":");
Serial.print(packet.localPort());
Serial.print(", Length: ");
Serial.print(packet.length());
Serial.print(", Data: ");
Serial.write(packet.data(), packet.length());
Serial.println();
//reply to the client
packet.printf("Got %u bytes of data", packet.length());
});
//Send multicast
udp.print("Hello!");
}
}
void loop()
{
delay(1000);
//Send multicast
udp.print("Anyone here?");
}

View File

@ -1,50 +0,0 @@
#include <ESP8266WiFi.h>
#include "ESPAsyncUDP.h"
const char * ssid = "***********";
const char * password = "***********";
AsyncUDP udp;
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed");
while(1) {
delay(1000);
}
}
if(udp.listen(1234)) {
Serial.print("UDP Listening on IP: ");
Serial.println(WiFi.localIP());
udp.onPacket([](AsyncUDPPacket packet) {
Serial.print("UDP Packet Type: ");
Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast");
Serial.print(", From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.print(packet.remotePort());
Serial.print(", To: ");
Serial.print(packet.localIP());
Serial.print(":");
Serial.print(packet.localPort());
Serial.print(", Length: ");
Serial.print(packet.length());
Serial.print(", Data: ");
Serial.write(packet.data(), packet.length());
Serial.println();
//reply to the client
packet.printf("Got %u bytes of data", packet.length());
});
}
}
void loop()
{
delay(1000);
//Send broadcast
udp.broadcast("Anyone here?");
}

View File

@ -1,17 +0,0 @@
{
"name":"ESPAsyncUDP",
"description":"Asynchronous UDP Library for ESP8266",
"keywords":"async,udp,server,client,multicast,broadcast",
"authors":
{
"name": "Hristo Gochkov",
"maintainer": true
},
"repository":
{
"type": "git",
"url": "https://github.com/me-no-dev/ESPAsyncUDP.git"
},
"frameworks": "arduino",
"platforms":"espressif"
}

View File

@ -1,9 +0,0 @@
name=ESP Async UDP
version=1.0.0
author=Me-No-Dev
maintainer=Me-No-Dev
sentence=Async UDP Library for ESP8266
paragraph=Async UDP Library for ESP8266
category=Other
url=https://github.com/me-no-dev/ESPAsyncUDP
architectures=*

View File

@ -1,432 +0,0 @@
#include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 // This Library will only work with ARDUINO_ESP8266_RELEASE_2_4_0 and up
#include "Arduino.h"
#include "ESPAsyncUDP.h"
extern "C" {
#include "user_interface.h"
#include "lwip/opt.h"
#include "lwip/inet.h"
#include "lwip/udp.h"
#include "lwip/igmp.h"
}
AsyncUDPMessage::AsyncUDPMessage(size_t size)
{
_index = 0;
if(size > 1460) {
size = 1460;
}
_size = size;
_buffer = (uint8_t *)malloc(size);
}
AsyncUDPMessage::~AsyncUDPMessage()
{
if(_buffer) {
free(_buffer);
}
}
size_t AsyncUDPMessage::write(const uint8_t *data, size_t len)
{
if(_buffer == NULL) {
return 0;
}
size_t s = space();
if(len > s) {
len = s;
}
memcpy(_buffer + _index, data, len);
_index += len;
return len;
}
size_t AsyncUDPMessage::write(uint8_t data)
{
return write(&data, 1);
}
size_t AsyncUDPMessage::space()
{
if(_buffer == NULL) {
return 0;
}
return _size - _index;
}
uint8_t * AsyncUDPMessage::data()
{
return _buffer;
}
size_t AsyncUDPMessage::length()
{
return _index;
}
void AsyncUDPMessage::flush()
{
_index = 0;
}
AsyncUDPPacket::AsyncUDPPacket(AsyncUDP *udp, ip_addr_t *localIp, uint16_t localPort, ip_addr_t *remoteIp, uint16_t remotePort, uint8_t *data, size_t len)
{
_udp = udp;
_localIp = localIp;
_localPort = localPort;
_remoteIp = remoteIp;
_remotePort = remotePort;
_data = data;
_len = len;
}
AsyncUDPPacket::~AsyncUDPPacket()
{
}
uint8_t * AsyncUDPPacket::data()
{
return _data;
}
size_t AsyncUDPPacket::length()
{
return _len;
}
IPAddress AsyncUDPPacket::localIP()
{
return IPAddress(_localIp->addr);
}
uint16_t AsyncUDPPacket::localPort()
{
return _localPort;
}
IPAddress AsyncUDPPacket::remoteIP()
{
return IPAddress(_remoteIp->addr);
}
uint16_t AsyncUDPPacket::remotePort()
{
return _remotePort;
}
bool AsyncUDPPacket::isBroadcast()
{
return _localIp->addr == 0xFFFFFFFF || _localIp->addr == (uint32_t)(0);
}
bool AsyncUDPPacket::isMulticast()
{
return ip_addr_ismulticast(_localIp);
}
size_t AsyncUDPPacket::write(const uint8_t *data, size_t len)
{
return _udp->writeTo(data, len, _remoteIp, _remotePort);
}
size_t AsyncUDPPacket::write(uint8_t data)
{
return write(&data, 1);
}
size_t AsyncUDPPacket::send(AsyncUDPMessage &message)
{
return write(message.data(), message.length());
}
AsyncUDP::AsyncUDP()
{
_pcb = NULL;
_connected = false;
_handler = NULL;
}
AsyncUDP::~AsyncUDP()
{
close();
}
AsyncUDP::operator bool()
{
return _connected;
}
bool AsyncUDP::connected()
{
return _connected;
}
void AsyncUDP::onPacket(AuPacketHandlerFunctionWithArg cb, void * arg)
{
onPacket(std::bind(cb, arg, std::placeholders::_1));
}
void AsyncUDP::onPacket(AuPacketHandlerFunction cb)
{
_handler = cb;
}
void AsyncUDP::_recv(udp_pcb *upcb, pbuf *pb, ip_addr_t *addr, uint16_t port)
{
(void)upcb; // its unused, avoid warning
while(pb != NULL) {
if(_handler) {
uint8_t * data = (uint8_t*)((pb)->payload);
size_t len = pb->len;
ip_hdr* iphdr = reinterpret_cast<ip_hdr*>(data - UDP_HLEN - IP_HLEN);
ip_addr_t daddr;
daddr.addr = iphdr->dest.addr;
udp_hdr* udphdr = reinterpret_cast<udp_hdr*>(((uint8_t*)((pb)->payload)) - UDP_HLEN);
uint16_t dport = ntohs(udphdr->dest);
AsyncUDPPacket packet(this, &daddr, dport, addr, port, data, len);
_handler(packet);
}
pbuf * this_pb = pb;
pb = pb->next;
this_pb->next = NULL;
pbuf_free(this_pb);
}
}
#if LWIP_VERSION_MAJOR == 1
void AsyncUDP::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, ip_addr_t *addr, uint16_t port)
#else
void AsyncUDP::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port)
#endif
{
reinterpret_cast<AsyncUDP*>(arg)->_recv(upcb, p, (ip_addr_t *)addr, port);
}
bool AsyncUDP::listen(ip_addr_t *addr, uint16_t port)
{
close();
_pcb = udp_new();
if(_pcb == NULL) {
return false;
}
err_t err = udp_bind(_pcb, addr, port);
if(err != ERR_OK) {
close();
return false;
}
udp_recv(_pcb, &_s_recv, (void *) this);
_connected = true;
return true;
}
bool AsyncUDP::listenMulticast(ip_addr_t *addr, uint16_t port, uint8_t ttl)
{
close();
if(!ip_addr_ismulticast(addr)) {
return false;
}
ip_addr_t multicast_if_addr;
struct ip_info ifIpInfo;
int mode = wifi_get_opmode();
if(mode & STATION_MODE) {
wifi_get_ip_info(STATION_IF, &ifIpInfo);
multicast_if_addr.addr = ifIpInfo.ip.addr;
} else if (mode & SOFTAP_MODE) {
wifi_get_ip_info(SOFTAP_IF, &ifIpInfo);
multicast_if_addr.addr = ifIpInfo.ip.addr;
} else {
return false;
}
if (igmp_joingroup(&multicast_if_addr, addr)!= ERR_OK) {
return false;
}
if(!listen(IPADDR_ANY, port)) {
return false;
}
#if LWIP_VERSION_MAJOR == 1
udp_set_multicast_netif_addr(_pcb, multicast_if_addr);
#else
udp_set_multicast_netif_addr(_pcb, &multicast_if_addr);
#endif
udp_set_multicast_ttl(_pcb, ttl);
ip_addr_copy(_pcb->remote_ip, *addr);
_pcb->remote_port = port;
return true;
}
bool AsyncUDP::connect(ip_addr_t *addr, uint16_t port)
{
close();
_pcb = udp_new();
if(_pcb == NULL) {
return false;
}
err_t err = udp_connect(_pcb, addr, port);
if(err != ERR_OK) {
close();
return false;
}
udp_recv(_pcb, &_s_recv, (void *) this);
_connected = true;
return true;
}
void AsyncUDP::close()
{
if(_pcb != NULL) {
if(_connected) {
udp_disconnect(_pcb);
}
udp_remove(_pcb);
_connected = false;
_pcb = NULL;
}
}
size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, ip_addr_t *addr, uint16_t port)
{
if(!_pcb && !connect(addr, port)) {
return 0;
}
if(len > 1460) {
len = 1460;
}
pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
if(pbt != NULL) {
uint8_t* dst = reinterpret_cast<uint8_t*>(pbt->payload);
memcpy(dst, data, len);
err_t err = udp_sendto(_pcb, pbt, addr, port);
pbuf_free(pbt);
if(err < ERR_OK) {
return 0;
}
return len;
}
return 0;
}
bool AsyncUDP::listen(const IPAddress addr, uint16_t port)
{
ip_addr_t laddr;
laddr.addr = addr;
return listen(&laddr, port);
}
bool AsyncUDP::listen(uint16_t port)
{
return listen(IPAddress((uint32_t)INADDR_ANY), port);
}
bool AsyncUDP::listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl)
{
ip_addr_t laddr;
laddr.addr = addr;
return listenMulticast(&laddr, port, ttl);
}
bool AsyncUDP::connect(const IPAddress addr, uint16_t port)
{
ip_addr_t daddr;
daddr.addr = addr;
return connect(&daddr, port);
}
size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port)
{
ip_addr_t daddr;
daddr.addr = addr;
return writeTo(data, len, &daddr, port);
}
size_t AsyncUDP::write(const uint8_t *data, size_t len)
{
//return writeTo(data, len, &(_pcb->remote_ip), _pcb->remote_port);
if(_pcb){ // Patch applied (https://github.com/me-no-dev/ESPAsyncUDP/pull/21)
return writeTo(data, len, &(_pcb->remote_ip), _pcb->remote_port);
}
return 0;
}
size_t AsyncUDP::write(uint8_t data)
{
return write(&data, 1);
}
size_t AsyncUDP::broadcastTo(uint8_t *data, size_t len, uint16_t port)
{
ip_addr_t daddr;
daddr.addr = 0xFFFFFFFF;
return writeTo(data, len, &daddr, port);
}
size_t AsyncUDP::broadcastTo(const char * data, uint16_t port)
{
return broadcastTo((uint8_t *)data, strlen(data), port);
}
size_t AsyncUDP::broadcast(uint8_t *data, size_t len)
{
if(_pcb->local_port != 0) {
return broadcastTo(data, len, _pcb->local_port);
}
return 0;
}
size_t AsyncUDP::broadcast(const char * data)
{
return broadcast((uint8_t *)data, strlen(data));
}
size_t AsyncUDP::sendTo(AsyncUDPMessage &message, ip_addr_t *addr, uint16_t port)
{
if(!message) {
return 0;
}
return writeTo(message.data(), message.length(), addr, port);
}
size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port)
{
//if(!message) {
if((!message) || (!_pcb)) { // Patch applied (https://github.com/me-no-dev/ESPAsyncUDP/pull/21)
return 0;
}
return writeTo(message.data(), message.length(), addr, port);
}
size_t AsyncUDP::send(AsyncUDPMessage &message)
{
if(!message) {
return 0;
}
return writeTo(message.data(), message.length(), &(_pcb->remote_ip), _pcb->remote_port);
}
size_t AsyncUDP::broadcastTo(AsyncUDPMessage &message, uint16_t port)
{
if(!message) {
return 0;
}
return broadcastTo(message.data(), message.length(), port);
}
size_t AsyncUDP::broadcast(AsyncUDPMessage &message)
{
if(!message) {
return 0;
}
return broadcast(message.data(), message.length());
}
#endif

View File

@ -1,130 +0,0 @@
#ifndef ESPASYNCUDP_H
#define ESPASYNCUDP_H
#include "IPAddress.h"
#include "Print.h"
#include <functional>
#include "lwip/init.h"
class AsyncUDP;
class AsyncUDPPacket;
class AsyncUDPMessage;
struct udp_pcb;
struct pbuf;
#if LWIP_VERSION_MAJOR == 1
struct ip_addr;
typedef struct ip_addr ip_addr_t;
#else
struct ip4_addr;
typedef struct ip4_addr ip_addr_t;
#endif
class AsyncUDPMessage : public Print
{
protected:
uint8_t *_buffer;
size_t _index;
size_t _size;
public:
AsyncUDPMessage(size_t size=1460);
virtual ~AsyncUDPMessage();
size_t write(const uint8_t *data, size_t len);
size_t write(uint8_t data);
size_t space();
uint8_t * data();
size_t length();
void flush();
operator bool()
{
return _buffer != NULL;
}
};
class AsyncUDPPacket : public Print
{
protected:
AsyncUDP *_udp;
ip_addr_t *_localIp;
uint16_t _localPort;
ip_addr_t *_remoteIp;
uint16_t _remotePort;
uint8_t *_data;
size_t _len;
public:
AsyncUDPPacket(AsyncUDP *udp, ip_addr_t *localIp, uint16_t localPort, ip_addr_t *remoteIp, uint16_t remotePort, uint8_t *data, size_t len);
virtual ~AsyncUDPPacket();
uint8_t * data();
size_t length();
bool isBroadcast();
bool isMulticast();
IPAddress localIP();
uint16_t localPort();
IPAddress remoteIP();
uint16_t remotePort();
size_t send(AsyncUDPMessage &message);
size_t write(const uint8_t *data, size_t len);
size_t write(uint8_t data);
};
typedef std::function<void(AsyncUDPPacket& packet)> AuPacketHandlerFunction;
typedef std::function<void(void * arg, AsyncUDPPacket& packet)> AuPacketHandlerFunctionWithArg;
class AsyncUDP : public Print
{
protected:
udp_pcb *_pcb;
bool _connected;
AuPacketHandlerFunction _handler;
void _recv(udp_pcb *upcb, pbuf *pb, ip_addr_t *addr, uint16_t port);
#if LWIP_VERSION_MAJOR == 1
static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, ip_addr_t *addr, uint16_t port);
#else
static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port);
#endif
public:
AsyncUDP();
virtual ~AsyncUDP();
void onPacket(AuPacketHandlerFunctionWithArg cb, void * arg=NULL);
void onPacket(AuPacketHandlerFunction cb);
bool listen(ip_addr_t *addr, uint16_t port);
bool listen(const IPAddress addr, uint16_t port);
bool listen(uint16_t port);
bool listenMulticast(ip_addr_t *addr, uint16_t port, uint8_t ttl=1);
bool listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl=1);
bool connect(ip_addr_t *addr, uint16_t port);
bool connect(const IPAddress addr, uint16_t port);
void close();
size_t writeTo(const uint8_t *data, size_t len, ip_addr_t *addr, uint16_t port);
size_t writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port);
size_t write(const uint8_t *data, size_t len);
size_t write(uint8_t data);
size_t broadcastTo(uint8_t *data, size_t len, uint16_t port);
size_t broadcastTo(const char * data, uint16_t port);
size_t broadcast(uint8_t *data, size_t len);
size_t broadcast(const char * data);
size_t sendTo(AsyncUDPMessage &message, ip_addr_t *addr, uint16_t port);
size_t sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port);
size_t send(AsyncUDPMessage &message);
size_t broadcastTo(AsyncUDPMessage &message, uint16_t port);
size_t broadcast(AsyncUDPMessage &message);
bool connected();
operator bool();
};
#endif

View File

@ -1,23 +0,0 @@
#!/bin/bash
function build_sketches()
{
local arduino=$1
local srcpath=$2
local platform=$3
local sketches=$(find $srcpath -name *.ino)
for sketch in $sketches; do
local sketchdir=$(dirname $sketch)
if [[ -f "$sketchdir/.$platform.skip" ]]; then
echo -e "\n\n ------------ Skipping $sketch ------------ \n\n";
continue
fi
echo -e "\n\n ------------ Building $sketch ------------ \n\n";
$arduino --verify $sketch;
local result=$?
if [ $result -ne 0 ]; then
echo "Build failed ($1)"
return $result
fi
done
}

View File

@ -1,39 +0,0 @@
import unittest
import settings
import time
import mosquitto
def on_message(mosq, obj, msg):
obj.message_queue.append(msg)
class mqtt_basic(unittest.TestCase):
message_queue = []
@classmethod
def setUpClass(self):
self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self)
self.client.connect(settings.server_ip)
self.client.on_message = on_message
self.client.subscribe("outTopic", 0)
@classmethod
def tearDownClass(self):
self.client.disconnect()
def test_one(self):
i = 30
while len(self.message_queue) == 0 and i > 0:
self.client.loop()
time.sleep(0.5)
i -= 1
self.assertTrue(i > 0, "message receive timed-out")
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
msg = self.message_queue[0]
self.assertEqual(msg.mid, 0, "message id not 0")
self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
self.assertEqual(msg.payload, "hello world")
self.assertEqual(msg.qos, 0, "message qos not 0")
self.assertEqual(msg.retain, False, "message retain flag incorrect")

View File

@ -1,59 +0,0 @@
import unittest
import settings
import time
import mosquitto
def on_message(mosq, obj, msg):
obj.message_queue.append(msg)
class mqtt_publish_in_callback(unittest.TestCase):
message_queue = []
@classmethod
def setUpClass(self):
self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self)
self.client.connect(settings.server_ip)
self.client.on_message = on_message
self.client.subscribe("outTopic", 0)
@classmethod
def tearDownClass(self):
self.client.disconnect()
def test_connect(self):
i = 30
while len(self.message_queue) == 0 and i > 0:
self.client.loop()
time.sleep(0.5)
i -= 1
self.assertTrue(i > 0, "message receive timed-out")
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
msg = self.message_queue.pop(0)
self.assertEqual(msg.mid, 0, "message id not 0")
self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
self.assertEqual(msg.payload, "hello world")
self.assertEqual(msg.qos, 0, "message qos not 0")
self.assertEqual(msg.retain, False, "message retain flag incorrect")
def test_publish(self):
self.assertEqual(len(self.message_queue), 0, "message queue not empty")
payload = "abcdefghij"
self.client.publish("inTopic", payload)
i = 30
while len(self.message_queue) == 0 and i > 0:
self.client.loop()
time.sleep(0.5)
i -= 1
self.assertTrue(i > 0, "message receive timed-out")
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
msg = self.message_queue.pop(0)
self.assertEqual(msg.mid, 0, "message id not 0")
self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
self.assertEqual(msg.payload, payload)
self.assertEqual(msg.qos, 0, "message qos not 0")
self.assertEqual(msg.retain, False, "message retain flag incorrect")

View File

@ -1,181 +0,0 @@
#!/usr/bin/env python
import os
import os.path
import sys
import shutil
from subprocess import call
import importlib
import unittest
import re
from testcases import settings
class Workspace(object):
def __init__(self):
self.root_dir = os.getcwd()
self.build_dir = os.path.join(self.root_dir, "tmpbin")
self.log_dir = os.path.join(self.root_dir, "logs")
self.tests_dir = os.path.join(self.root_dir, "testcases")
self.examples_dir = os.path.join(self.root_dir, "../PubSubClient/examples")
self.examples = []
self.tests = []
if not os.path.isdir("../PubSubClient"):
raise Exception("Cannot find PubSubClient library")
try:
return __import__('ino')
except ImportError:
raise Exception("ino tool not installed")
def init(self):
if os.path.isdir(self.build_dir):
shutil.rmtree(self.build_dir)
os.mkdir(self.build_dir)
if os.path.isdir(self.log_dir):
shutil.rmtree(self.log_dir)
os.mkdir(self.log_dir)
os.chdir(self.build_dir)
call(["ino", "init"])
shutil.copytree("../../PubSubClient", "lib/PubSubClient")
filenames = []
for root, dirs, files in os.walk(self.examples_dir):
filenames += [os.path.join(root, f) for f in files if f.endswith(".ino")]
filenames.sort()
for e in filenames:
self.examples.append(Sketch(self, e))
filenames = []
for root, dirs, files in os.walk(self.tests_dir):
filenames += [os.path.join(root, f) for f in files if f.endswith(".ino")]
filenames.sort()
for e in filenames:
self.tests.append(Sketch(self, e))
def clean(self):
shutil.rmtree(self.build_dir)
class Sketch(object):
def __init__(self, wksp, fn):
self.w = wksp
self.filename = fn
self.basename = os.path.basename(self.filename)
self.build_log = os.path.join(self.w.log_dir, "%s.log" % (os.path.basename(self.filename),))
self.build_err_log = os.path.join(self.w.log_dir, "%s.err.log" % (os.path.basename(self.filename),))
self.build_upload_log = os.path.join(self.w.log_dir, "%s.upload.log" % (os.path.basename(self.filename),))
def build(self):
sys.stdout.write(" Build: ")
sys.stdout.flush()
# Copy sketch over, replacing IP addresses as necessary
fin = open(self.filename, "r")
lines = fin.readlines()
fin.close()
fout = open(os.path.join(self.w.build_dir, "src", "sketch.ino"), "w")
for l in lines:
if re.match(r"^byte server\[\] = {", l):
fout.write("byte server[] = { %s };\n" % (settings.server_ip.replace(".", ", "),))
elif re.match(r"^byte ip\[\] = {", l):
fout.write("byte ip[] = { %s };\n" % (settings.arduino_ip.replace(".", ", "),))
else:
fout.write(l)
fout.flush()
fout.close()
# Run build
fout = open(self.build_log, "w")
ferr = open(self.build_err_log, "w")
rc = call(["ino", "build"], stdout=fout, stderr=ferr)
fout.close()
ferr.close()
if rc == 0:
sys.stdout.write("pass")
sys.stdout.write("\n")
return True
else:
sys.stdout.write("fail")
sys.stdout.write("\n")
with open(self.build_err_log) as f:
for line in f:
print(" " + line)
return False
def upload(self):
sys.stdout.write(" Upload: ")
sys.stdout.flush()
fout = open(self.build_upload_log, "w")
rc = call(["ino", "upload"], stdout=fout, stderr=fout)
fout.close()
if rc == 0:
sys.stdout.write("pass")
sys.stdout.write("\n")
return True
else:
sys.stdout.write("fail")
sys.stdout.write("\n")
with open(self.build_upload_log) as f:
for line in f:
print(" " + line)
return False
def test(self):
# import the matching test case, if it exists
try:
basename = os.path.basename(self.filename)[:-4]
i = importlib.import_module("testcases." + basename)
except:
sys.stdout.write(" Test: no tests found")
sys.stdout.write("\n")
return
c = getattr(i, basename)
testmethods = [m for m in dir(c) if m.startswith("test_")]
testmethods.sort()
tests = []
for m in testmethods:
tests.append(c(m))
result = unittest.TestResult()
c.setUpClass()
if self.upload():
sys.stdout.write(" Test: ")
sys.stdout.flush()
for t in tests:
t.run(result)
print(str(result.testsRun - len(result.failures) - len(result.errors)) + "/" + str(result.testsRun))
if not result.wasSuccessful():
if len(result.failures) > 0:
for f in result.failures:
print("-- " + str(f[0]))
print(f[1])
if len(result.errors) > 0:
print(" Errors:")
for f in result.errors:
print("-- " + str(f[0]))
print(f[1])
c.tearDownClass()
if __name__ == '__main__':
run_tests = True
w = Workspace()
w.init()
for e in w.examples:
print("--------------------------------------")
print("[" + e.basename + "]")
if e.build() and run_tests:
e.test()
for e in w.tests:
print("--------------------------------------")
print("[" + e.basename + "]")
if e.build() and run_tests:
e.test()
w.clean()

View File

@ -38,6 +38,14 @@ long lastMsg = 0;
char msg[50];
int value = 0;
void setup() {
pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void setup_wifi() {
delay(10);
@ -53,8 +61,6 @@ void setup_wifi() {
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
@ -85,11 +91,8 @@ void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
if (client.connect("ESP8266Client")) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("outTopic", "hello world");
@ -104,15 +107,6 @@ void reconnect() {
}
}
}
void setup() {
pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {

View File

@ -117,8 +117,8 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
if (!connected()) {
int result = 0;
if (domain != NULL) {
result = _client->connect(this->domain, this->port);
if (domain.length() != 0) {
result = _client->connect(this->domain.c_str(), this->port);
} else {
result = _client->connect(this->ip, this->port);
}
@ -209,7 +209,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
boolean PubSubClient::readByte(uint8_t * result) {
uint32_t previousMillis = millis();
while(!_client->available()) {
delay(1); // Add esp8266 de-blocking (Tasmota #790)
delay(1); // Add esp8266 de-blocking (Tasmota #790, EspEasy #1943)
uint32_t currentMillis = millis();
if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
return false;
@ -241,11 +241,17 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
uint8_t start = 0;
do {
if (len == 6) {
// Invalid remaining length encoding - kill the connection
_state = MQTT_DISCONNECTED;
_client->stop();
return 0;
}
if(!readByte(&digit)) return 0;
buffer[len++] = digit;
length += (digit & 127) * multiplier;
multiplier *= 128;
} while ((digit & 128) != 0);
} while ((digit & 128) != 0 && len < (MQTT_MAX_PACKET_SIZE -2));
*lengthLength = len-1;
if (isPublish) {
@ -336,6 +342,9 @@ boolean PubSubClient::loop() {
} else if (type == MQTTPINGRESP) {
pingOutstanding = false;
}
} else if (!connected()) {
// readPacket has closed the connection
return false;
}
}
return true;
@ -419,7 +428,7 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig
lastOutActivity = millis();
return rc == tlen + 4 + plength;
return rc == tlen + 3 + llen + plength;
}
boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
@ -469,7 +478,7 @@ boolean PubSubClient::subscribe(const char* topic) {
}
boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
if (qos < 0 || qos > 1) {
if (qos > 1) {
return false;
}
if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
@ -514,9 +523,12 @@ boolean PubSubClient::unsubscribe(const char* topic) {
void PubSubClient::disconnect() {
buffer[0] = MQTTDISCONNECT;
buffer[1] = 0;
_client->write(buffer,2);
if (_client != NULL) {
_client->write(buffer,2);
_client->flush();
_client->stop();
}
_state = MQTT_DISCONNECTED;
_client->stop();
lastInActivity = lastOutActivity = millis();
}
@ -524,7 +536,7 @@ uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t po
const char* idp = string;
uint16_t i = 0;
pos += 2;
while (*idp) {
while (*idp && pos < (MQTT_MAX_PACKET_SIZE - 2)) {
buf[pos++] = *idp++;
i++;
}
@ -559,7 +571,7 @@ PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) {
PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) {
this->ip = ip;
this->port = port;
this->domain = NULL;
this->domain = "";
return *this;
}

View File

@ -24,13 +24,13 @@
// MQTT_MAX_PACKET_SIZE : Maximum packet size
#ifndef MQTT_MAX_PACKET_SIZE
//#define MQTT_MAX_PACKET_SIZE 128
//#define MQTT_MAX_PACKET_SIZE 512 // Tasmota
#define MQTT_MAX_PACKET_SIZE 1000 // Tasmota v5.11.1c
#endif
// MQTT_KEEPALIVE : keepAlive interval in Seconds
// Keepalive timeout for default MQTT Broker is 10s
#ifndef MQTT_KEEPALIVE
#define MQTT_KEEPALIVE 15
#define MQTT_KEEPALIVE 10
#endif
// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
@ -75,7 +75,7 @@
#define MQTTQOS1 (1 << 1)
#define MQTTQOS2 (2 << 1)
#ifdef ESP8266
#if defined(ESP8266) || defined(ESP32)
#include <functional>
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
#else
@ -97,7 +97,7 @@ private:
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
IPAddress ip;
const char* domain;
String domain;
uint16_t port;
Stream* stream;
int _state;
@ -116,6 +116,7 @@ public:
PubSubClient(const char*, uint16_t, Client& client, Stream&);
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
virtual ~PubSubClient() {}
PubSubClient& setServer(IPAddress ip, uint16_t port);
PubSubClient& setServer(uint8_t * ip, uint16_t port);

View File

@ -133,23 +133,6 @@ int test_connect_accepts_username_no_password() {
END_IT
}
int test_connect_accepts_username_blank_password() {
IT("accepts a username and blank password");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte connect[] = { 0x10,0x20,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x0};
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
shimClient.expect(connect,0x26);
shimClient.respond(connack,4);
PubSubClient client(server, 1883, callback, shimClient);
int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass");
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_connect_ignores_password_no_username() {
IT("ignores a password but no username");

View File

@ -2,13 +2,9 @@
#include "Arduino.h"
Buffer::Buffer() {
this->pos = 0;
this->length = 0;
}
Buffer::Buffer(uint8_t* buf, size_t size) {
this->pos = 0;
this->length = 0;
this->add(buf,size);
}
bool Buffer::available() {

View File

@ -0,0 +1,43 @@
import unittest
import settings
import time
import mosquitto
import serial
def on_message(mosq, obj, msg):
obj.message_queue.append(msg)
class mqtt_basic(unittest.TestCase):
message_queue = []
@classmethod
def setUpClass(self):
self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self)
self.client.connect(settings.server_ip)
self.client.on_message = on_message
self.client.subscribe("outTopic",0)
@classmethod
def tearDownClass(self):
self.client.disconnect()
def test_one(self):
i=30
while len(self.message_queue) == 0 and i > 0:
self.client.loop()
time.sleep(0.5)
i -= 1
self.assertTrue(i>0, "message receive timed-out")
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
msg = self.message_queue[0]
self.assertEqual(msg.mid,0,"message id not 0")
self.assertEqual(msg.topic,"outTopic","message topic incorrect")
self.assertEqual(msg.payload,"hello world")
self.assertEqual(msg.qos,0,"message qos not 0")
self.assertEqual(msg.retain,False,"message retain flag incorrect")

View File

@ -0,0 +1,64 @@
import unittest
import settings
import time
import mosquitto
import serial
def on_message(mosq, obj, msg):
obj.message_queue.append(msg)
class mqtt_publish_in_callback(unittest.TestCase):
message_queue = []
@classmethod
def setUpClass(self):
self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self)
self.client.connect(settings.server_ip)
self.client.on_message = on_message
self.client.subscribe("outTopic",0)
@classmethod
def tearDownClass(self):
self.client.disconnect()
def test_connect(self):
i=30
while len(self.message_queue) == 0 and i > 0:
self.client.loop()
time.sleep(0.5)
i -= 1
self.assertTrue(i>0, "message receive timed-out")
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
msg = self.message_queue.pop(0)
self.assertEqual(msg.mid,0,"message id not 0")
self.assertEqual(msg.topic,"outTopic","message topic incorrect")
self.assertEqual(msg.payload,"hello world")
self.assertEqual(msg.qos,0,"message qos not 0")
self.assertEqual(msg.retain,False,"message retain flag incorrect")
def test_publish(self):
self.assertEqual(len(self.message_queue), 0, "message queue not empty")
payload = "abcdefghij"
self.client.publish("inTopic",payload)
i=30
while len(self.message_queue) == 0 and i > 0:
self.client.loop()
time.sleep(0.5)
i -= 1
self.assertTrue(i>0, "message receive timed-out")
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
msg = self.message_queue.pop(0)
self.assertEqual(msg.mid,0,"message id not 0")
self.assertEqual(msg.topic,"outTopic","message topic incorrect")
self.assertEqual(msg.payload,payload)
self.assertEqual(msg.qos,0,"message qos not 0")
self.assertEqual(msg.retain,False,"message retain flag incorrect")

View File

@ -0,0 +1,179 @@
#!/usr/bin/env python
import os
import os.path
import sys
import shutil
from subprocess import call
import importlib
import unittest
import re
from testcases import settings
class Workspace(object):
def __init__(self):
self.root_dir = os.getcwd()
self.build_dir = os.path.join(self.root_dir,"tmpbin");
self.log_dir = os.path.join(self.root_dir,"logs");
self.tests_dir = os.path.join(self.root_dir,"testcases");
self.examples_dir = os.path.join(self.root_dir,"../PubSubClient/examples")
self.examples = []
self.tests = []
if not os.path.isdir("../PubSubClient"):
raise Exception("Cannot find PubSubClient library")
try:
import ino
except:
raise Exception("ino tool not installed")
def init(self):
if os.path.isdir(self.build_dir):
shutil.rmtree(self.build_dir)
os.mkdir(self.build_dir)
if os.path.isdir(self.log_dir):
shutil.rmtree(self.log_dir)
os.mkdir(self.log_dir)
os.chdir(self.build_dir)
call(["ino","init"])
shutil.copytree("../../PubSubClient","lib/PubSubClient")
filenames = []
for root, dirs, files in os.walk(self.examples_dir):
filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")]
filenames.sort()
for e in filenames:
self.examples.append(Sketch(self,e))
filenames = []
for root, dirs, files in os.walk(self.tests_dir):
filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")]
filenames.sort()
for e in filenames:
self.tests.append(Sketch(self,e))
def clean(self):
shutil.rmtree(self.build_dir)
class Sketch(object):
def __init__(self,wksp,fn):
self.w = wksp
self.filename = fn
self.basename = os.path.basename(self.filename)
self.build_log = os.path.join(self.w.log_dir,"%s.log"%(os.path.basename(self.filename),))
self.build_err_log = os.path.join(self.w.log_dir,"%s.err.log"%(os.path.basename(self.filename),))
self.build_upload_log = os.path.join(self.w.log_dir,"%s.upload.log"%(os.path.basename(self.filename),))
def build(self):
sys.stdout.write(" Build: ")
sys.stdout.flush()
# Copy sketch over, replacing IP addresses as necessary
fin = open(self.filename,"r")
lines = fin.readlines()
fin.close()
fout = open(os.path.join(self.w.build_dir,"src","sketch.ino"),"w")
for l in lines:
if re.match(r"^byte server\[\] = {",l):
fout.write("byte server[] = { %s };\n"%(settings.server_ip.replace(".",", "),))
elif re.match(r"^byte ip\[\] = {",l):
fout.write("byte ip[] = { %s };\n"%(settings.arduino_ip.replace(".",", "),))
else:
fout.write(l)
fout.flush()
fout.close()
# Run build
fout = open(self.build_log, "w")
ferr = open(self.build_err_log, "w")
rc = call(["ino","build"],stdout=fout,stderr=ferr)
fout.close()
ferr.close()
if rc == 0:
sys.stdout.write("pass")
sys.stdout.write("\n")
return True
else:
sys.stdout.write("fail")
sys.stdout.write("\n")
with open(self.build_err_log) as f:
for line in f:
print " ",line,
return False
def upload(self):
sys.stdout.write(" Upload: ")
sys.stdout.flush()
fout = open(self.build_upload_log, "w")
rc = call(["ino","upload"],stdout=fout,stderr=fout)
fout.close()
if rc == 0:
sys.stdout.write("pass")
sys.stdout.write("\n")
return True
else:
sys.stdout.write("fail")
sys.stdout.write("\n")
with open(self.build_upload_log) as f:
for line in f:
print " ",line,
return False
def test(self):
# import the matching test case, if it exists
try:
basename = os.path.basename(self.filename)[:-4]
i = importlib.import_module("testcases."+basename)
except:
sys.stdout.write(" Test: no tests found")
sys.stdout.write("\n")
return
c = getattr(i,basename)
testmethods = [m for m in dir(c) if m.startswith("test_")]
testmethods.sort()
tests = []
for m in testmethods:
tests.append(c(m))
result = unittest.TestResult()
c.setUpClass()
if self.upload():
sys.stdout.write(" Test: ")
sys.stdout.flush()
for t in tests:
t.run(result)
print "%d/%d"%(result.testsRun-len(result.failures)-len(result.errors),result.testsRun)
if not result.wasSuccessful():
if len(result.failures) > 0:
for f in result.failures:
print "-- %s"%(str(f[0]),)
print f[1]
if len(result.errors) > 0:
print " Errors:"
for f in result.errors:
print "-- %s"%(str(f[0]),)
print f[1]
c.tearDownClass()
if __name__ == '__main__':
run_tests = True
w = Workspace()
w.init()
for e in w.examples:
print "--------------------------------------"
print "[%s]"%(e.basename,)
if e.build() and run_tests:
e.test()
for e in w.tests:
print "--------------------------------------"
print "[%s]"%(e.basename,)
if e.build() and run_tests:
e.test()
w.clean()

View File

@ -0,0 +1,31 @@
#include <TasmotaModbus.h>
TasmotaModbus Modbus(14, 12);
void setup() {
Serial.begin(115200);
Modbus.Begin(9600);
Serial.println("\nTasmotaModbus test started");
Modbus.Send(0x01, 0x04, 0, 8);
}
void loop() {
if (Modbus.ReceiveReady()) {
uint8_t buffer[26];
uint8_t error = Modbus.ReceiveBuffer(buffer, 8);
if (error) {
Serial.print("Modbus response error ");
Serial.println(error);
} else {
Serial.print("Modbus received:");
for (int i = 0; i < (buffer[2]) ? buffer[2] +5 : sizeof(buffer); i++) {
Serial.print(" ");
Serial.print(buffer[i], HEX);
}
}
}
}

View File

@ -1,33 +1,26 @@
#######################################
# Syntax Coloring Map For Ultrasound
# Syntax Coloring Map for TasmotaModbus
# (esp8266)
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
AsyncUDP KEYWORD1
AsyncUDPPacket KEYWORD1
TasmotaModbus KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
connect KEYWORD2
connected KEYWORD2
listen KEYWORD2
listenMulticast KEYWORD2
close KEYWORD2
write KEYWORD2
broadcast KEYWORD2
onPacket KEYWORD2
data KEYWORD2
length KEYWORD2
localIP KEYWORD2
localPort KEYWORD2
remoteIP KEYWORD2
remotePort KEYWORD2
Begin KEYWORD2
Send KEYWORD2
ReceiveReady KEYWORD2
ReceiveBuffer KEYWORD2
Receive16BitRegister KEYWORD2
Receive32BitRegister KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -0,0 +1,15 @@
{
"name": "TasmotaModbus",
"version": "1.1.0",
"keywords": [
"serial", "io", "TasmotaModbus"
],
"description": "Basic modbus wrapper for TasmotaSerial for ESP8266.",
"repository":
{
"type": "git",
"url": "https://github.com/arendst/Sonoff-Tasmota/lib/TasmotaModbus"
},
"frameworks": "arduino",
"platforms": "espressif8266"
}

View File

@ -0,0 +1,9 @@
name=TasmotaModbus
version=1.1.0
author=Theo Arends
maintainer=Theo Arends <theo@arends.com>
sentence=Basic modbus wrapper for TasmotaSerial for ESP8266.
paragraph=
category=Signal Input/Output
url=
architectures=esp8266

View File

@ -0,0 +1,147 @@
/*
TasmotaModbus.cpp - Basic modbus wrapper for TasmotaSerial for Tasmota
Copyright (C) 2018 Theo Arends
This library 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 <http://www.gnu.org/licenses/>.
*/
#include "TasmotaModbus.h"
TasmotaModbus::TasmotaModbus(int receive_pin, int transmit_pin) : TasmotaSerial(receive_pin, transmit_pin, 1)
{
mb_address = 0;
}
uint16_t CalculateCRC(uint8_t *frame, uint8_t num)
{
uint16_t crc = 0xFFFF;
uint16_t flag;
for (uint8_t i = 0; i < num; i++) {
crc ^= frame[i];
for (uint8_t j = 8; j; j--) {
if ((crc & 0x0001) != 0) { // If the LSB is set
crc >>= 1; // Shift right and XOR 0xA001
crc ^= 0xA001;
} else { // Else LSB is not set
crc >>= 1; // Just shift right
}
}
}
return crc;
}
int TasmotaModbus::Begin(long speed, int stop_bits)
{
int result = 0;
if (begin(speed, stop_bits)) {
result = 1;
if (hardwareSerial()) { result = 2; }
}
return result;
}
void TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint16_t start_address, uint16_t register_count)
{
uint8_t frame[8];
mb_address = device_address; // Save address for receipt check
frame[0] = mb_address; // 0xFE default device address or dedicated like 0x01
frame[1] = function_code;
frame[2] = (uint8_t)(start_address >> 8);
frame[3] = (uint8_t)(start_address);
frame[4] = (uint8_t)(register_count >> 8);
frame[5] = (uint8_t)(register_count);
uint16_t crc = CalculateCRC(frame, 6);
frame[6] = (uint8_t)(crc);
frame[7] = (uint8_t)(crc >> 8);
flush();
write(frame, sizeof(frame));
}
bool TasmotaModbus::ReceiveReady()
{
return (available() > 4);
}
uint8_t TasmotaModbus::ReceiveBuffer(uint8_t *buffer, uint8_t register_count)
{
uint8_t len = 0;
uint32_t last = millis();
while ((available() > 0) && (len < (register_count *2) + 5) && (millis() - last < 10)) {
uint8_t data = (uint8_t)read();
if (!len) { // Skip leading data as provided by hardware serial
if (mb_address == data) {
buffer[len++] = data;
}
} else {
buffer[len++] = data;
if (3 == len) {
if (buffer[1] & 0x80) { // 01 84 02 f2 f1
return buffer[2]; // 1 = Illegal Function, 2 = Illegal Address, 3 = Illegal Data, 4 = Slave Error
}
}
}
last = millis();
}
if (len < 7) { return 7; } // 7 = Not enough data
if (len != buffer[2] + 5) { return 8; } // 8 = Unexpected result
uint16_t crc = (buffer[len -1] << 8) | buffer[len -2];
if (CalculateCRC(buffer, len -2) != crc) { return 9; } // 9 = crc error
return 0; // 0 = No error
}
uint8_t TasmotaModbus::Receive16BitRegister(uint16_t *value)
{
// 0 1 2 3 4 5 6
// 01 04 02 43 21 HH LL
// Id Cc Sz Regis Crc--
uint8_t buffer[7];
uint8_t error = ReceiveBuffer(buffer, 1); // 1 x 16bit register
if (!error) {
*value = (buffer[3] << 8) | buffer[4];
}
return error;
}
uint8_t TasmotaModbus::Receive32BitRegister(float *value)
{
// 0 1 2 3 4 5 6 7 8
// 01 04 04 87 65 43 21 HH LL
// Id Cc Sz Register--- Crc--
uint8_t buffer[9];
*value = NAN;
uint8_t error = ReceiveBuffer(buffer, 2); // 1 x 32bit register
if (!error) {
((uint8_t*)value)[3] = buffer[3];
((uint8_t*)value)[2] = buffer[4];
((uint8_t*)value)[1] = buffer[5];
((uint8_t*)value)[0] = buffer[6];
}
return error;
}

View File

@ -0,0 +1,57 @@
/*
TasmotaModbus.h - Basic modbus wrapper for TasmotaSerial for Tasmota
Copyright (C) 2018 Theo Arends
This library 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TasmotaModbus_h
#define TasmotaModbus_h
#include <Arduino.h>
#include <TasmotaSerial.h>
#define TM_MODBUS_BAUDRATE 9600 // Default baudrate
class TasmotaModbus : public TasmotaSerial {
public:
TasmotaModbus(int receive_pin, int transmit_pin);
virtual ~TasmotaModbus() {}
int Begin(long speed = TM_MODBUS_BAUDRATE, int stop_bits = 1);
void Send(uint8_t device_address, uint8_t function_code, uint16_t start_address, uint16_t register_count);
bool ReceiveReady();
/* Return codes:
* 0 - No error
* 1 - Illegal function
* 2 - Illegal address
* 3 - Illegal data
* 4 - Slave error
* 7 - Not enough minimal data received
* 8 - Not enough data receieved
* 9 - Crc error
*/
uint8_t ReceiveBuffer(uint8_t *buffer, uint8_t register_count);
uint8_t Receive16BitRegister(uint16_t *value);
uint8_t Receive32BitRegister(float *value);
private:
uint8_t mb_address;
};
#endif // TasmotaModbus_h

View File

@ -0,0 +1,7 @@
# TasmotaSerial
Implementation of software serial with hardware serial fallback library for the ESP8266
Allows for several instances to be active at the same time.
Please note that due to the fact that the ESP always have other activities ongoing, there will be some inexactness in interrupt timings. This may lead to bit errors when having heavy data traffic.

View File

@ -1,6 +1,6 @@
{
"name": "TasmotaSerial",
"version": "2.0.0",
"version": "2.1.0",
"keywords": [
"serial", "io", "TasmotaSerial"
],

View File

@ -1,5 +1,5 @@
name=TasmotaSerial
version=2.0.0
version=2.1.0
author=Theo Arends
maintainer=Theo Arends <theo@arends.com>
sentence=Implementation of software serial with hardware serial fallback for ESP8266.

View File

@ -80,6 +80,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, bool hardware_fa
{
m_valid = false;
m_hardserial = 0;
m_stop_bits = 1;
if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) {
return;
}
@ -106,15 +107,33 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, bool hardware_fa
m_valid = true;
}
TasmotaSerial::~TasmotaSerial()
{
if (!m_hardserial) {
if (m_rx_pin > -1) {
detachInterrupt(m_rx_pin);
tms_obj_list[m_rx_pin] = NULL;
if (m_buffer) {
free(m_buffer);
}
}
}
}
bool TasmotaSerial::isValidGPIOpin(int pin)
{
return (pin >= -1 && pin <= 5) || (pin >= 12 && pin <= 15);
}
bool TasmotaSerial::begin(long speed) {
bool TasmotaSerial::begin(long speed, int stop_bits) {
m_stop_bits = ((stop_bits -1) &1) +1;
if (m_hardserial) {
Serial.flush();
Serial.begin(speed, SERIAL_8N1);
if (2 == m_stop_bits) {
Serial.begin(speed, SERIAL_8N2);
} else {
Serial.begin(speed, SERIAL_8N1);
}
} else {
// Use getCycleCount() loop to get as exact timing as possible
m_bit_time = ESP.getCpuFreqMHz() *1000000 /speed;
@ -195,9 +214,11 @@ size_t TasmotaSerial::write(uint8_t b)
TM_SERIAL_WAIT;
b >>= 1;
}
// Stop bit
digitalWrite(m_tx_pin, HIGH);
TM_SERIAL_WAIT;
// Stop bit(s)
for (int i = 0; i < m_stop_bits; i++) {
digitalWrite(m_tx_pin, HIGH);
TM_SERIAL_WAIT;
}
if (m_high_speed) sei();
return 1;
}
@ -220,8 +241,12 @@ void TasmotaSerial::rxRead()
rec >>= 1;
if (digitalRead(m_rx_pin)) rec |= 0x80;
}
// Stop bit
// Stop bit(s)
TM_SERIAL_WAIT;
if (2 == m_stop_bits) {
digitalRead(m_rx_pin);
TM_SERIAL_WAIT;
}
// Store the received value in the buffer unless we have an overflow
int next = (m_in_pos+1) % TM_SERIAL_BUFFER_SIZE;
if (next != (int)m_out_pos) {

View File

@ -33,12 +33,15 @@
#define TM_SERIAL_USE_IRAM // Enable to use iram (+368 bytes)
#endif
#include <inttypes.h>
#include <Stream.h>
class TasmotaSerial : public Stream {
public:
TasmotaSerial(int receive_pin, int transmit_pin, bool hardware_fallback = false);
bool begin(long speed);
virtual ~TasmotaSerial();
bool begin(long speed, int stop_bits = 1);
bool begin();
bool hardwareSerial();
int peek();
@ -62,6 +65,7 @@ class TasmotaSerial : public Stream {
bool m_high_speed;
int m_rx_pin;
int m_tx_pin;
int m_stop_bits;
unsigned long m_bit_time;
unsigned int m_in_pos;
unsigned int m_out_pos;

View File

@ -0,0 +1,9 @@
name=Waveshare esp 2.9 inch e-paper display driver
version=1.0
author=Gerhard Muntz
maintainer=Gerhard Muntz
sentence=ESP8266 library for Waveshare e-paper display.
paragraph=
category=Display
url=https://github.com/gemu2015/Sonoff-Tasmota/tree/displays/lib/esp-epaper-29-ws-20171230-gemu-1.0#
architectures=esp8266

View File

@ -77,13 +77,10 @@ void ESPKNXIP::send(address_t const &receiver, knx_command_type_t ct, uint8_t da
DEBUG_PRINTLN(F(""));
#endif
#ifdef USE_ASYNC_UDP
udp.writeTo(buf, len, MULTICAST_IP, MULTICAST_PORT);
#else
udp.beginPacketMulticast(MULTICAST_IP, MULTICAST_PORT, WiFi.localIP());
udp.write(buf, len);
udp.endPacket();
#endif
}
void ESPKNXIP::send_1bit(address_t const &receiver, knx_command_type_t ct, uint8_t bit)

View File

@ -95,13 +95,7 @@ void ESPKNXIP::__start()
#endif
server->begin();
}
#ifdef USE_ASYNC_UDP
udp.listenMulticast(MULTICAST_IP, MULTICAST_PORT);
udp.onPacket([this](AsyncUDPPacket &packet) { __loop_knx(packet); });
#else
udp.beginMulticast(WiFi.localIP(), MULTICAST_IP, MULTICAST_PORT);
#endif
}
void ESPKNXIP::save_to_eeprom()
@ -516,9 +510,7 @@ feedback_id_t ESPKNXIP::feedback_register_action(String name, feedback_action_fp
void ESPKNXIP::loop()
{
#ifndef USE_ASYNC_UDP
__loop_knx();
#endif
if (server != nullptr)
{
__loop_webserver();
@ -530,15 +522,9 @@ void ESPKNXIP::__loop_webserver()
server->handleClient();
}
#ifdef USE_ASYNC_UDP
void ESPKNXIP::__loop_knx(AsyncUDPPacket &packet)
{
size_t read = packet.length();
#else
void ESPKNXIP::__loop_knx()
{
int read = udp.parsePacket();
#endif
if (!read)
{
@ -548,23 +534,15 @@ void ESPKNXIP::__loop_knx()
DEBUG_PRINT(F("LEN: "));
DEBUG_PRINTLN(read);
#ifdef USE_ASYNC_UDP
uint8_t *buf = packet.data();
#else
uint8_t buf[read];
udp.read(buf, read);
udp.flush();
#endif
DEBUG_PRINT(F("Got packet:"));
#ifdef ESP_KNX_DEBUG
#ifdef USE_ASYNC_UDP
for (size_t i = 0; i < read; ++i)
#else
for (int i = 0; i < read; ++i)
#endif
{
DEBUG_PRINT(F(" 0x"));

View File

@ -45,18 +45,7 @@
#include "Arduino.h"
#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
#define USE_ASYNC_UDP // UDP WIFI Library Selection for Multicast
#endif
#ifdef USE_ASYNC_UDP
#include <ESPAsyncUDP.h>
#else
#include <WiFiUdp.h>
#endif
#include <ESP8266WebServer.h>
#include "DPT.h"
@ -529,11 +518,7 @@ class ESPKNXIP {
private:
void __start();
#ifdef USE_ASYNC_UDP
void __loop_knx(AsyncUDPPacket &packet);
#else
void __loop_knx();
#endif
// Webserver functions
void __loop_webserver();
@ -569,11 +554,7 @@ class ESPKNXIP {
ESP8266WebServer *server;
address_t physaddr;
#ifdef USE_ASYNC_UDP
AsyncUDP udp;
#else
WiFiUDP udp;
#endif
callback_assignment_id_t registered_callback_assignments;
callback_assignment_id_t free_callback_assignment_slots;

17
lib/rc-switch-2.6.2.13/.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
# Mac stuff
.DS_Store
# Compiled Object files
*.slo
*.lo
*.o
# Compiled Dynamic libraries
*.so
*.dylib
# Compiled Static libraries
*.lai
*.la
*.a

View File

@ -0,0 +1,69 @@
language: c
python:
- "2.7"
# Cache PlatformIO packages using Travis CI container-based infrastructure
cache:
pip: true
directories:
- "~/.platformio"
env:
- >
PLATFORMIO_CI_SRC=$PWD/examples/Webserver
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/Webserver.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
- >
PLATFORMIO_CI_SRC=$PWD/examples/ReceiveDemo_Simple
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/ReceiveDemo_Simple.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
- >
PLATFORMIO_CI_SRC=$PWD/examples/TypeC_Intertechno
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeC_Intertechno.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
- >
PLATFORMIO_CI_SRC=$PWD/examples/TypeD_REV
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeD_REV.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
- >
PLATFORMIO_CI_SRC=$PWD/examples/TypeA_WithDIPSwitches
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeA_WithDIPSwitches.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
- >
PLATFORMIO_CI_SRC=$PWD/examples/TypeA_WithDIPSwitches_Lightweight
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeA_WithDIPSwitches_Lightweight.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
- >
PLATFORMIO_CI_SRC=$PWD/examples/TypeB_WithRotaryOrSlidingSwitches
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeB_WithRotaryOrSlidingSwitches.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
- >
PLATFORMIO_CI_SRC=$PWD/examples/SendDemo
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/SendDemo.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
- >
PLATFORMIO_CI_SRC=$PWD/examples/ReceiveDemo_Advanced
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/ReceiveDemo_Advanced.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
before_install:
# Arduino IDE
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16"
- sleep 3
- export DISPLAY=:1.0
- wget http://downloads.arduino.cc/arduino-1.6.9-linux64.tar.xz
- tar xf arduino-1.6.9-linux64.tar.xz
- sudo mv arduino-1.6.9 /usr/local/share/arduino
- sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino
install:
# Arduino IDE
- ln -s $PWD /usr/local/share/arduino/libraries/rc-switch
# PlatformIO
- sudo pip install -U platformio
script:
# Arduino IDE
- arduino --verify --board arduino:avr:uno ${ARDUINOIDE_CI_SRC}
# PlatformIO
- platformio ci --lib="." ${BOARDS}

View File

@ -0,0 +1,701 @@
/*
RCSwitch - Arduino libary for remote control outlet switches
Copyright (c) 2011 Suat Özgür. All right reserved.
Contributors:
- Andre Koehler / info(at)tomate-online(dot)de
- Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
- Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
- Dominik Fischer / dom_fischer(at)web(dot)de
- Frank Oltmanns / <first name>.<last name>(at)gmail(dot)com
- Andreas Steinel / A.<lastname>(at)gmail(dot)com
- Max Horn / max(at)quendi(dot)de
- Robert ter Vehn / <first name>.<last name>(at)gmail(dot)com
- Johann Richard / <first name>.<last name>(at)gmail(dot)com
- Vlad Gheorghe / <first name>.<last name>(at)gmail(dot)com https://github.com/vgheo
Project home: https://github.com/sui77/rc-switch/
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 "RCSwitch.h"
#ifdef RaspberryPi
// PROGMEM and _P functions are for AVR based microprocessors,
// so we must normalize these for the ARM processor:
#define PROGMEM
#define memcpy_P(dest, src, num) memcpy((dest), (src), (num))
#endif
#if defined(ESP8266) || defined(ESP32)
// interrupt handler and related code must be in RAM on ESP8266,
// according to issue #46.
#define RECEIVE_ATTR ICACHE_RAM_ATTR
#else
#define RECEIVE_ATTR
#endif
/* Format for protocol definitions:
* {pulselength, Sync bit, "0" bit, "1" bit}
*
* pulselength: pulse length in microseconds, e.g. 350
* Sync bit: {1, 31} means 1 high pulse and 31 low pulses
* (perceived as a 31*pulselength long pulse, total length of sync bit is
* 32*pulselength microseconds), i.e:
* _
* | |_______________________________ (don't count the vertical bars)
* "0" bit: waveform for a data bit of value "0", {1, 3} means 1 high pulse
* and 3 low pulses, total length (1+3)*pulselength, i.e:
* _
* | |___
* "1" bit: waveform for a data bit of value "1", e.g. {3,1}:
* ___
* | |_
*
* These are combined to form Tri-State bits when sending or receiving codes.
*/
#if defined(ESP8266) || defined(ESP32)
static const RCSwitch::Protocol proto[] = {
#else
static const RCSwitch::Protocol PROGMEM proto[] = {
#endif
{ 350, { 1, 31 }, { 1, 3 }, { 3, 1 }, false }, // protocol 1
{ 650, { 1, 10 }, { 1, 2 }, { 2, 1 }, false }, // protocol 2
{ 100, { 30, 71 }, { 4, 11 }, { 9, 6 }, false }, // protocol 3
{ 380, { 1, 6 }, { 1, 3 }, { 3, 1 }, false }, // protocol 4
{ 500, { 6, 14 }, { 1, 2 }, { 2, 1 }, false }, // protocol 5
{ 450, { 23, 1 }, { 1, 2 }, { 2, 1 }, true }, // protocol 6 (HT6P20B)
{ 150, { 2, 62 }, { 1, 6 }, { 6, 1 }, false } // protocol 7 (HS2303-PT, i. e. used in AUKEY Remote)
};
enum {
numProto = sizeof(proto) / sizeof(proto[0])
};
#if not defined( RCSwitchDisableReceiving )
volatile unsigned long RCSwitch::nReceivedValue = 0;
volatile unsigned int RCSwitch::nReceivedBitlength = 0;
volatile unsigned int RCSwitch::nReceivedDelay = 0;
volatile unsigned int RCSwitch::nReceivedProtocol = 0;
int RCSwitch::nReceiveTolerance = 60;
const unsigned int RCSwitch::nSeparationLimit = 4300;
// separationLimit: minimum microseconds between received codes, closer codes are ignored.
// according to discussion on issue #14 it might be more suitable to set the separation
// limit to the same time as the 'low' part of the sync signal for the current protocol.
unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES];
#endif
RCSwitch::RCSwitch() {
this->nTransmitterPin = -1;
this->setRepeatTransmit(10);
this->setProtocol(1);
#if not defined( RCSwitchDisableReceiving )
this->nReceiverInterrupt = -1;
this->setReceiveTolerance(60);
RCSwitch::nReceivedValue = 0;
#endif
}
/**
* Sets the protocol to send.
*/
void RCSwitch::setProtocol(Protocol protocol) {
this->protocol = protocol;
}
/**
* Sets the protocol to send, from a list of predefined protocols
*/
void RCSwitch::setProtocol(int nProtocol) {
if (nProtocol < 1 || nProtocol > numProto) {
nProtocol = 1; // TODO: trigger an error, e.g. "bad protocol" ???
}
#if defined(ESP8266) || defined(ESP32)
this->protocol = proto[nProtocol-1];
#else
memcpy_P(&this->protocol, &proto[nProtocol-1], sizeof(Protocol));
#endif
}
/**
* Sets the protocol to send with pulse length in microseconds.
*/
void RCSwitch::setProtocol(int nProtocol, int nPulseLength) {
setProtocol(nProtocol);
this->setPulseLength(nPulseLength);
}
/**
* Sets pulse length in microseconds
*/
void RCSwitch::setPulseLength(int nPulseLength) {
this->protocol.pulseLength = nPulseLength;
}
/**
* Sets Repeat Transmits
*/
void RCSwitch::setRepeatTransmit(int nRepeatTransmit) {
this->nRepeatTransmit = nRepeatTransmit;
}
/**
* Set Receiving Tolerance
*/
#if not defined( RCSwitchDisableReceiving )
void RCSwitch::setReceiveTolerance(int nPercent) {
RCSwitch::nReceiveTolerance = nPercent;
}
#endif
/**
* Enable transmissions
*
* @param nTransmitterPin Arduino Pin to which the sender is connected to
*/
void RCSwitch::enableTransmit(int nTransmitterPin) {
this->nTransmitterPin = nTransmitterPin;
pinMode(this->nTransmitterPin, OUTPUT);
}
/**
* Disable transmissions
*/
void RCSwitch::disableTransmit() {
this->nTransmitterPin = -1;
}
/**
* Switch a remote switch on (Type D REV)
*
* @param sGroup Code of the switch group (A,B,C,D)
* @param nDevice Number of the switch itself (1..3)
*/
void RCSwitch::switchOn(char sGroup, int nDevice) {
this->sendTriState( this->getCodeWordD(sGroup, nDevice, true) );
}
/**
* Switch a remote switch off (Type D REV)
*
* @param sGroup Code of the switch group (A,B,C,D)
* @param nDevice Number of the switch itself (1..3)
*/
void RCSwitch::switchOff(char sGroup, int nDevice) {
this->sendTriState( this->getCodeWordD(sGroup, nDevice, false) );
}
/**
* Switch a remote switch on (Type C Intertechno)
*
* @param sFamily Familycode (a..f)
* @param nGroup Number of group (1..4)
* @param nDevice Number of device (1..4)
*/
void RCSwitch::switchOn(char sFamily, int nGroup, int nDevice) {
this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, true) );
}
/**
* Switch a remote switch off (Type C Intertechno)
*
* @param sFamily Familycode (a..f)
* @param nGroup Number of group (1..4)
* @param nDevice Number of device (1..4)
*/
void RCSwitch::switchOff(char sFamily, int nGroup, int nDevice) {
this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, false) );
}
/**
* Switch a remote switch on (Type B with two rotary/sliding switches)
*
* @param nAddressCode Number of the switch group (1..4)
* @param nChannelCode Number of the switch itself (1..4)
*/
void RCSwitch::switchOn(int nAddressCode, int nChannelCode) {
this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, true) );
}
/**
* Switch a remote switch off (Type B with two rotary/sliding switches)
*
* @param nAddressCode Number of the switch group (1..4)
* @param nChannelCode Number of the switch itself (1..4)
*/
void RCSwitch::switchOff(int nAddressCode, int nChannelCode) {
this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, false) );
}
/**
* Deprecated, use switchOn(const char* sGroup, const char* sDevice) instead!
* Switch a remote switch on (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param nChannelCode Number of the switch itself (1..5)
*/
void RCSwitch::switchOn(const char* sGroup, int nChannel) {
const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
this->switchOn(sGroup, code[nChannel]);
}
/**
* Deprecated, use switchOff(const char* sGroup, const char* sDevice) instead!
* Switch a remote switch off (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param nChannelCode Number of the switch itself (1..5)
*/
void RCSwitch::switchOff(const char* sGroup, int nChannel) {
const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
this->switchOff(sGroup, code[nChannel]);
}
/**
* Switch a remote switch on (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
*/
void RCSwitch::switchOn(const char* sGroup, const char* sDevice) {
this->sendTriState( this->getCodeWordA(sGroup, sDevice, true) );
}
/**
* Switch a remote switch off (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
*/
void RCSwitch::switchOff(const char* sGroup, const char* sDevice) {
this->sendTriState( this->getCodeWordA(sGroup, sDevice, false) );
}
/**
* Returns a char[13], representing the code word to be send.
*
*/
char* RCSwitch::getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus) {
static char sReturn[13];
int nReturnPos = 0;
for (int i = 0; i < 5; i++) {
sReturn[nReturnPos++] = (sGroup[i] == '0') ? 'F' : '0';
}
for (int i = 0; i < 5; i++) {
sReturn[nReturnPos++] = (sDevice[i] == '0') ? 'F' : '0';
}
sReturn[nReturnPos++] = bStatus ? '0' : 'F';
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* Encoding for type B switches with two rotary/sliding switches.
*
* The code word is a tristate word and with following bit pattern:
*
* +-----------------------------+-----------------------------+----------+------------+
* | 4 bits address | 4 bits address | 3 bits | 1 bit |
* | switch group | switch number | not used | on / off |
* | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | FFF | on=F off=0 |
* +-----------------------------+-----------------------------+----------+------------+
*
* @param nAddressCode Number of the switch group (1..4)
* @param nChannelCode Number of the switch itself (1..4)
* @param bStatus Whether to switch on (true) or off (false)
*
* @return char[13], representing a tristate code word of length 12
*/
char* RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) {
static char sReturn[13];
int nReturnPos = 0;
if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) {
return 0;
}
for (int i = 1; i <= 4; i++) {
sReturn[nReturnPos++] = (nAddressCode == i) ? '0' : 'F';
}
for (int i = 1; i <= 4; i++) {
sReturn[nReturnPos++] = (nChannelCode == i) ? '0' : 'F';
}
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* Like getCodeWord (Type C = Intertechno)
*/
char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) {
static char sReturn[13];
int nReturnPos = 0;
int nFamily = (int)sFamily - 'a';
if ( nFamily < 0 || nFamily > 15 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) {
return 0;
}
// encode the family into four bits
sReturn[nReturnPos++] = (nFamily & 1) ? 'F' : '0';
sReturn[nReturnPos++] = (nFamily & 2) ? 'F' : '0';
sReturn[nReturnPos++] = (nFamily & 4) ? 'F' : '0';
sReturn[nReturnPos++] = (nFamily & 8) ? 'F' : '0';
// encode the device and group
sReturn[nReturnPos++] = ((nDevice-1) & 1) ? 'F' : '0';
sReturn[nReturnPos++] = ((nDevice-1) & 2) ? 'F' : '0';
sReturn[nReturnPos++] = ((nGroup-1) & 1) ? 'F' : '0';
sReturn[nReturnPos++] = ((nGroup-1) & 2) ? 'F' : '0';
// encode the status code
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* Encoding for the REV Switch Type
*
* The code word is a tristate word and with following bit pattern:
*
* +-----------------------------+-------------------+----------+--------------+
* | 4 bits address | 3 bits address | 3 bits | 2 bits |
* | switch group | device number | not used | on / off |
* | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FF 2=F0F 3=FF0 | 000 | on=10 off=01 |
* +-----------------------------+-------------------+----------+--------------+
*
* Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/
*
* @param sGroup Name of the switch group (A..D, resp. a..d)
* @param nDevice Number of the switch itself (1..3)
* @param bStatus Whether to switch on (true) or off (false)
*
* @return char[13], representing a tristate code word of length 12
*/
char* RCSwitch::getCodeWordD(char sGroup, int nDevice, bool bStatus) {
static char sReturn[13];
int nReturnPos = 0;
// sGroup must be one of the letters in "abcdABCD"
int nGroup = (sGroup >= 'a') ? (int)sGroup - 'a' : (int)sGroup - 'A';
if ( nGroup < 0 || nGroup > 3 || nDevice < 1 || nDevice > 3) {
return 0;
}
for (int i = 0; i < 4; i++) {
sReturn[nReturnPos++] = (nGroup == i) ? '1' : 'F';
}
for (int i = 1; i <= 3; i++) {
sReturn[nReturnPos++] = (nDevice == i) ? '1' : 'F';
}
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = bStatus ? '1' : '0';
sReturn[nReturnPos++] = bStatus ? '0' : '1';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* @param sCodeWord a tristate code word consisting of the letter 0, 1, F
*/
void RCSwitch::sendTriState(const char* sCodeWord) {
// turn the tristate code word into the corresponding bit pattern, then send it
unsigned long code = 0;
unsigned int length = 0;
for (const char* p = sCodeWord; *p; p++) {
code <<= 2L;
switch (*p) {
case '0':
// bit pattern 00
break;
case 'F':
// bit pattern 01
code |= 1L;
break;
case '1':
// bit pattern 11
code |= 3L;
break;
}
length += 2;
}
this->send(code, length);
}
/**
* @param sCodeWord a binary code word consisting of the letter 0, 1
*/
void RCSwitch::send(const char* sCodeWord) {
// turn the tristate code word into the corresponding bit pattern, then send it
unsigned long code = 0;
unsigned int length = 0;
for (const char* p = sCodeWord; *p; p++) {
code <<= 1L;
if (*p != '0')
code |= 1L;
length++;
}
this->send(code, length);
}
/**
* Transmit the first 'length' bits of the integer 'code'. The
* bits are sent from MSB to LSB, i.e., first the bit at position length-1,
* then the bit at position length-2, and so on, till finally the bit at position 0.
*/
void RCSwitch::send(unsigned long code, unsigned int length) {
if (this->nTransmitterPin == -1)
return;
#if not defined( RCSwitchDisableReceiving )
// make sure the receiver is disabled while we transmit
int nReceiverInterrupt_backup = nReceiverInterrupt;
if (nReceiverInterrupt_backup != -1) {
this->disableReceive();
}
#endif
for (int nRepeat = 0; nRepeat < nRepeatTransmit; nRepeat++) {
for (int i = length-1; i >= 0; i--) {
if (code & (1L << i))
this->transmit(protocol.one);
else
this->transmit(protocol.zero);
}
this->transmit(protocol.syncFactor);
}
// Disable transmit after sending (i.e., for inverted protocols)
digitalWrite(this->nTransmitterPin, LOW);
#if not defined( RCSwitchDisableReceiving )
// enable receiver again if we just disabled it
if (nReceiverInterrupt_backup != -1) {
this->enableReceive(nReceiverInterrupt_backup);
}
#endif
}
/**
* Transmit a single high-low pulse.
*/
void RCSwitch::transmit(HighLow pulses) {
uint8_t firstLogicLevel = (this->protocol.invertedSignal) ? LOW : HIGH;
uint8_t secondLogicLevel = (this->protocol.invertedSignal) ? HIGH : LOW;
digitalWrite(this->nTransmitterPin, firstLogicLevel);
delayMicroseconds( this->protocol.pulseLength * pulses.high);
digitalWrite(this->nTransmitterPin, secondLogicLevel);
delayMicroseconds( this->protocol.pulseLength * pulses.low);
}
#if not defined( RCSwitchDisableReceiving )
/**
* Enable receiving data
*/
void RCSwitch::enableReceive(int interrupt) {
this->nReceiverInterrupt = interrupt;
this->enableReceive();
}
void RCSwitch::enableReceive() {
if (this->nReceiverInterrupt != -1) {
RCSwitch::nReceivedValue = 0;
RCSwitch::nReceivedBitlength = 0;
#if defined(RaspberryPi) // Raspberry Pi
wiringPiISR(this->nReceiverInterrupt, INT_EDGE_BOTH, &handleInterrupt);
#else // Arduino
attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE);
#endif
}
}
/**
* Disable receiving data
*/
void RCSwitch::disableReceive() {
#if not defined(RaspberryPi) // Arduino
detachInterrupt(this->nReceiverInterrupt);
#endif // For Raspberry Pi (wiringPi) you can't unregister the ISR
this->nReceiverInterrupt = -1;
}
bool RCSwitch::available() {
return RCSwitch::nReceivedValue != 0;
}
void RCSwitch::resetAvailable() {
RCSwitch::nReceivedValue = 0;
}
unsigned long RCSwitch::getReceivedValue() {
return RCSwitch::nReceivedValue;
}
unsigned int RCSwitch::getReceivedBitlength() {
return RCSwitch::nReceivedBitlength;
}
unsigned int RCSwitch::getReceivedDelay() {
return RCSwitch::nReceivedDelay;
}
unsigned int RCSwitch::getReceivedProtocol() {
return RCSwitch::nReceivedProtocol;
}
unsigned int* RCSwitch::getReceivedRawdata() {
return RCSwitch::timings;
}
/* helper function for the receiveProtocol method */
static inline unsigned int diff(int A, int B) {
return abs(A - B);
}
/**
*
*/
bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCount) {
#if defined(ESP8266) || defined(ESP32)
const Protocol &pro = proto[p-1];
#else
Protocol pro;
memcpy_P(&pro, &proto[p-1], sizeof(Protocol));
#endif
unsigned long code = 0;
//Assuming the longer pulse length is the pulse captured in timings[0]
const unsigned int syncLengthInPulses = ((pro.syncFactor.low) > (pro.syncFactor.high)) ? (pro.syncFactor.low) : (pro.syncFactor.high);
const unsigned int delay = RCSwitch::timings[0] / syncLengthInPulses;
const unsigned int delayTolerance = delay * RCSwitch::nReceiveTolerance / 100;
/* For protocols that start low, the sync period looks like
* _________
* _____________| |XXXXXXXXXXXX|
*
* |--1st dur--|-2nd dur-|-Start data-|
*
* The 3rd saved duration starts the data.
*
* For protocols that start high, the sync period looks like
*
* ______________
* | |____________|XXXXXXXXXXXXX|
*
* |-filtered out-|--1st dur--|--Start data--|
*
* The 2nd saved duration starts the data
*/
const unsigned int firstDataTiming = (pro.invertedSignal) ? (2) : (1);
for (unsigned int i = firstDataTiming; i < changeCount - 1; i += 2) {
code <<= 1;
if (diff(RCSwitch::timings[i], delay * pro.zero.high) < delayTolerance &&
diff(RCSwitch::timings[i + 1], delay * pro.zero.low) < delayTolerance) {
// zero
} else if (diff(RCSwitch::timings[i], delay * pro.one.high) < delayTolerance &&
diff(RCSwitch::timings[i + 1], delay * pro.one.low) < delayTolerance) {
// one
code |= 1;
} else {
// Failed
return false;
}
}
if (changeCount > 7) { // ignore very short transmissions: no device sends them, so this must be noise
RCSwitch::nReceivedValue = code;
RCSwitch::nReceivedBitlength = (changeCount - 1) / 2;
RCSwitch::nReceivedDelay = delay;
RCSwitch::nReceivedProtocol = p;
return true;
}
return false;
}
void RECEIVE_ATTR RCSwitch::handleInterrupt() {
static unsigned int changeCount = 0;
static unsigned long lastTime = 0;
static unsigned int repeatCount = 0;
const long time = micros();
const unsigned int duration = time - lastTime;
if (duration > RCSwitch::nSeparationLimit) {
// A long stretch without signal level change occurred. This could
// be the gap between two transmission.
if (diff(duration, RCSwitch::timings[0]) < 200) {
// This long signal is close in length to the long signal which
// started the previously recorded timings; this suggests that
// it may indeed by a a gap between two transmissions (we assume
// here that a sender will send the signal multiple times,
// with roughly the same gap between them).
repeatCount++;
if (repeatCount == 2) {
for(unsigned int i = 1; i <= numProto; i++) {
if (receiveProtocol(i, changeCount)) {
// receive succeeded for protocol i
break;
}
}
repeatCount = 0;
}
}
changeCount = 0;
}
// detect overflow
if (changeCount >= RCSWITCH_MAX_CHANGES) {
changeCount = 0;
repeatCount = 0;
}
RCSwitch::timings[changeCount++] = duration;
lastTime = time;
}
#endif

View File

@ -0,0 +1,184 @@
/*
RCSwitch - Arduino libary for remote control outlet switches
Copyright (c) 2011 Suat Özgür. All right reserved.
Contributors:
- Andre Koehler / info(at)tomate-online(dot)de
- Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
- Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
- Dominik Fischer / dom_fischer(at)web(dot)de
- Frank Oltmanns / <first name>.<last name>(at)gmail(dot)com
- Max Horn / max(at)quendi(dot)de
- Robert ter Vehn / <first name>.<last name>(at)gmail(dot)com
Project home: https://github.com/sui77/rc-switch/
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 _RCSwitch_h
#define _RCSwitch_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#elif defined(ENERGIA) // LaunchPad, FraunchPad and StellarPad specific
#include "Energia.h"
#elif defined(RPI) // Raspberry Pi
#define RaspberryPi
// Include libraries for RPi:
#include <string.h> /* memcpy */
#include <stdlib.h> /* abs */
#include <wiringPi.h>
#elif defined(SPARK)
#include "application.h"
#else
#include "WProgram.h"
#endif
#include <stdint.h>
// At least for the ATTiny X4/X5, receiving has to be disabled due to
// missing libm depencies (udivmodhi4)
#if defined( __AVR_ATtinyX5__ ) or defined ( __AVR_ATtinyX4__ )
#define RCSwitchDisableReceiving
#endif
// Number of maximum high/Low changes per packet.
// We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync
#define RCSWITCH_MAX_CHANGES 67
class RCSwitch {
public:
RCSwitch();
void switchOn(int nGroupNumber, int nSwitchNumber);
void switchOff(int nGroupNumber, int nSwitchNumber);
void switchOn(const char* sGroup, int nSwitchNumber);
void switchOff(const char* sGroup, int nSwitchNumber);
void switchOn(char sFamily, int nGroup, int nDevice);
void switchOff(char sFamily, int nGroup, int nDevice);
void switchOn(const char* sGroup, const char* sDevice);
void switchOff(const char* sGroup, const char* sDevice);
void switchOn(char sGroup, int nDevice);
void switchOff(char sGroup, int nDevice);
void sendTriState(const char* sCodeWord);
void send(unsigned long code, unsigned int length);
void send(const char* sCodeWord);
#if not defined( RCSwitchDisableReceiving )
void enableReceive(int interrupt);
void enableReceive();
void disableReceive();
bool available();
void resetAvailable();
unsigned long getReceivedValue();
unsigned int getReceivedBitlength();
unsigned int getReceivedDelay();
unsigned int getReceivedProtocol();
unsigned int* getReceivedRawdata();
#endif
void enableTransmit(int nTransmitterPin);
void disableTransmit();
void setPulseLength(int nPulseLength);
void setRepeatTransmit(int nRepeatTransmit);
#if not defined( RCSwitchDisableReceiving )
void setReceiveTolerance(int nPercent);
#endif
/**
* Description of a single pule, which consists of a high signal
* whose duration is "high" times the base pulse length, followed
* by a low signal lasting "low" times the base pulse length.
* Thus, the pulse overall lasts (high+low)*pulseLength
*/
struct HighLow {
uint8_t high;
uint8_t low;
};
/**
* A "protocol" describes how zero and one bits are encoded into high/low
* pulses.
*/
struct Protocol {
/** base pulse length in microseconds, e.g. 350 */
uint16_t pulseLength;
HighLow syncFactor;
HighLow zero;
HighLow one;
/**
* If true, interchange high and low logic levels in all transmissions.
*
* By default, RCSwitch assumes that any signals it sends or receives
* can be broken down into pulses which start with a high signal level,
* followed by a a low signal level. This is e.g. the case for the
* popular PT 2260 encoder chip, and thus many switches out there.
*
* But some devices do it the other way around, and start with a low
* signal level, followed by a high signal level, e.g. the HT6P20B. To
* accommodate this, one can set invertedSignal to true, which causes
* RCSwitch to change how it interprets any HighLow struct FOO: It will
* then assume transmissions start with a low signal lasting
* FOO.high*pulseLength microseconds, followed by a high signal lasting
* FOO.low*pulseLength microseconds.
*/
bool invertedSignal;
};
void setProtocol(Protocol protocol);
void setProtocol(int nProtocol);
void setProtocol(int nProtocol, int nPulseLength);
private:
char* getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus);
char* getCodeWordB(int nGroupNumber, int nSwitchNumber, bool bStatus);
char* getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus);
char* getCodeWordD(char group, int nDevice, bool bStatus);
void transmit(HighLow pulses);
#if not defined( RCSwitchDisableReceiving )
static void handleInterrupt();
static bool receiveProtocol(const int p, unsigned int changeCount);
int nReceiverInterrupt;
#endif
int nTransmitterPin;
int nRepeatTransmit;
Protocol protocol;
#if not defined( RCSwitchDisableReceiving )
static int nReceiveTolerance;
volatile static unsigned long nReceivedValue;
volatile static unsigned int nReceivedBitlength;
volatile static unsigned int nReceivedDelay;
volatile static unsigned int nReceivedProtocol;
const static unsigned int nSeparationLimit;
/*
* timings[0] contains sync timing, followed by a number of bits
*/
static unsigned int timings[RCSWITCH_MAX_CHANGES];
#endif
};
#endif

View File

@ -0,0 +1,41 @@
# rc-switch
[![Build Status](https://travis-ci.org/sui77/rc-switch.svg?branch=master)](https://travis-ci.org/sui77/rc-switch)
Use your Arduino or Raspberry Pi to operate remote radio controlled devices
## Download
https://github.com/sui77/rc-switch/releases/latest
rc-switch is also listed in the arduino library manager.
## Wiki
https://github.com/sui77/rc-switch/wiki
## Info
### Send RC codes
Use your Arduino or Raspberry Pi to operate remote radio controlled devices.
This will most likely work with all popular low cost power outlet sockets. If
yours doesn't work, you might need to adjust the pulse length.
All you need is a Arduino or Raspberry Pi, a 315/433MHz AM transmitter and one
or more devices with one of the supported chipsets:
- SC5262 / SC5272
- HX2262 / HX2272
- PT2262 / PT2272
- EV1527 / RT1527 / FP1527 / HS1527
- Intertechno outlets
- HT6P20X
### Receive and decode RC codes
Find out what codes your remote is sending. Use your remote to control your
Arduino.
All you need is an Arduino, a 315/433MHz AM receiver (altough there is no
instruction yet, yes it is possible to hack an existing device) and a remote
hand set.
For the Raspberry Pi, clone the https://github.com/ninjablocks/433Utils project to
compile a sniffer tool and transmission commands.

View File

@ -0,0 +1,24 @@
/*
Example for receiving
https://github.com/sui77/rc-switch/
If you want to visualize a telegram copy the raw data and
paste it into http://test.sui.li/oszi/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
Serial.begin(9600);
mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2
}
void loop() {
if (mySwitch.available()) {
output(mySwitch.getReceivedValue(), mySwitch.getReceivedBitlength(), mySwitch.getReceivedDelay(), mySwitch.getReceivedRawdata(),mySwitch.getReceivedProtocol());
mySwitch.resetAvailable();
}
}

View File

@ -0,0 +1,70 @@
static const char* bin2tristate(const char* bin);
static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength);
void output(unsigned long decimal, unsigned int length, unsigned int delay, unsigned int* raw, unsigned int protocol) {
const char* b = dec2binWzerofill(decimal, length);
Serial.print("Decimal: ");
Serial.print(decimal);
Serial.print(" (");
Serial.print( length );
Serial.print("Bit) Binary: ");
Serial.print( b );
Serial.print(" Tri-State: ");
Serial.print( bin2tristate( b) );
Serial.print(" PulseLength: ");
Serial.print(delay);
Serial.print(" microseconds");
Serial.print(" Protocol: ");
Serial.println(protocol);
Serial.print("Raw data: ");
for (unsigned int i=0; i<= length*2; i++) {
Serial.print(raw[i]);
Serial.print(",");
}
Serial.println();
Serial.println();
}
static const char* bin2tristate(const char* bin) {
static char returnValue[50];
int pos = 0;
int pos2 = 0;
while (bin[pos]!='\0' && bin[pos+1]!='\0') {
if (bin[pos]=='0' && bin[pos+1]=='0') {
returnValue[pos2] = '0';
} else if (bin[pos]=='1' && bin[pos+1]=='1') {
returnValue[pos2] = '1';
} else if (bin[pos]=='0' && bin[pos+1]=='1') {
returnValue[pos2] = 'F';
} else {
return "not applicable";
}
pos = pos+2;
pos2++;
}
returnValue[pos2] = '\0';
return returnValue;
}
static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength) {
static char bin[64];
unsigned int i=0;
while (Dec > 0) {
bin[32+i++] = ((Dec & 1) > 0) ? '1' : '0';
Dec = Dec >> 1;
}
for (unsigned int j = 0; j< bitLength; j++) {
if (j >= bitLength - i) {
bin[j] = bin[ 31 + i - (j - (bitLength - i)) ];
} else {
bin[j] = '0';
}
}
bin[bitLength] = '\0';
return bin;
}

View File

@ -0,0 +1,29 @@
/*
Simple example for receiving
https://github.com/sui77/rc-switch/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
Serial.begin(9600);
mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2
}
void loop() {
if (mySwitch.available()) {
Serial.print("Received ");
Serial.print( mySwitch.getReceivedValue() );
Serial.print(" / ");
Serial.print( mySwitch.getReceivedBitlength() );
Serial.print("bit ");
Serial.print("Protocol: ");
Serial.println( mySwitch.getReceivedProtocol() );
mySwitch.resetAvailable();
}
}

View File

@ -0,0 +1,57 @@
/*
Example for different sending methods
https://github.com/sui77/rc-switch/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
Serial.begin(9600);
// Transmitter is connected to Arduino Pin #10
mySwitch.enableTransmit(10);
// Optional set protocol (default is 1, will work for most outlets)
// mySwitch.setProtocol(2);
// Optional set pulse length.
// mySwitch.setPulseLength(320);
// Optional set number of transmission repetitions.
// mySwitch.setRepeatTransmit(15);
}
void loop() {
/* See Example: TypeA_WithDIPSwitches */
mySwitch.switchOn("11111", "00010");
delay(1000);
mySwitch.switchOff("11111", "00010");
delay(1000);
/* Same switch as above, but using decimal code */
mySwitch.send(5393, 24);
delay(1000);
mySwitch.send(5396, 24);
delay(1000);
/* Same switch as above, but using binary code */
mySwitch.send("000000000001010100010001");
delay(1000);
mySwitch.send("000000000001010100010100");
delay(1000);
/* Same switch as above, but tri-state code */
mySwitch.sendTriState("00000FFF0F0F");
delay(1000);
mySwitch.sendTriState("00000FFF0FF0");
delay(1000);
delay(20000);
}

View File

@ -0,0 +1,40 @@
/*
Example for outlets which are configured with a 10 pole DIP switch.
https://github.com/sui77/rc-switch/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
// Transmitter is connected to Arduino Pin #10
mySwitch.enableTransmit(10);
// Optional set pulse length.
// mySwitch.setPulseLength(320);
}
void loop() {
// Switch on:
// The first parameter represents the setting of the first 5 DIP switches.
// In this example it's ON-ON-OFF-OFF-ON.
//
// The second parameter represents the setting of the last 5 DIP switches.
// In this example the last 5 DIP switches are OFF-ON-OFF-ON-OFF.
mySwitch.switchOn("11001", "01010");
// Wait a second
delay(1000);
// Switch off
mySwitch.switchOff("11001", "01010");
// Wait another second
delay(1000);
}

View File

@ -0,0 +1,43 @@
/*
This is a minimal sketch without using the library at all but only works for
the 10 pole dip switch sockets. It saves a lot of memory and thus might be
very useful to use with ATTinys :)
https://github.com/sui77/rc-switch/
*/
int RCLpin = 7;
void setup() {
pinMode(RCLpin, OUTPUT);
}
void loop() {
RCLswitch(0b010001000001); // DIPs an Steckdose: 0100010000 An:01
delay(2000);
RCLswitch(0b010001000010); // DIPs an Steckdose: 0100010000 Aus:10
delay(2000);
}
void RCLswitch(uint16_t code) {
for (int nRepeat=0; nRepeat<6; nRepeat++) {
for (int i=4; i<16; i++) {
RCLtransmit(1,3);
if (((code << (i-4)) & 2048) > 0) {
RCLtransmit(1,3);
} else {
RCLtransmit(3,1);
}
}
RCLtransmit(1,31);
}
}
void RCLtransmit(int nHighPulses, int nLowPulses) {
digitalWrite(RCLpin, HIGH);
delayMicroseconds( 350 * nHighPulses);
digitalWrite(RCLpin, LOW);
delayMicroseconds( 350 * nLowPulses);
}

View File

@ -0,0 +1,40 @@
/*
Example for outlets which are configured with two rotary/sliding switches.
https://github.com/sui77/rc-switch/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
// Transmitter is connected to Arduino Pin #10
mySwitch.enableTransmit(10);
// Optional set pulse length.
// mySwitch.setPulseLength(320);
}
void loop() {
// Switch on:
// The first parameter represents the setting of the first rotary switch.
// In this example it's switched to "1" or "A" or "I".
//
// The second parameter represents the setting of the second rotary switch.
// In this example it's switched to "4" or "D" or "IV".
mySwitch.switchOn(1, 4);
// Wait a second
delay(1000);
// Switch off
mySwitch.switchOff(1, 4);
// Wait another second
delay(1000);
}

View File

@ -0,0 +1,40 @@
/*
Example for Intertechno outlets
https://github.com/sui77/rc-switch/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
// Transmitter is connected to Arduino Pin #10
mySwitch.enableTransmit(10);
// Optional set pulse length.
// mySwitch.setPulseLength(320);
}
void loop() {
// Switch on:
// The first parameter represents the familycode (a, b, c, ... f)
// The second parameter represents the group number
// The third parameter represents the device number
//
// In this example it's family 'b', group #3, device #2
mySwitch.switchOn('b', 3, 2);
// Wait a second
delay(1000);
// Switch off
mySwitch.switchOff('b', 3, 2);
// Wait another second
delay(1000);
}

View File

@ -0,0 +1,41 @@
/*
Example for REV outlets (e.g. 8342L)
https://github.com/sui77/rc-switch/
Need help? http://forum.ardumote.com
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
// Transmitter is connected to Arduino Pin #10
mySwitch.enableTransmit(10);
// set pulse length.
mySwitch.setPulseLength(360);
}
void loop() {
// Switch on:
// The first parameter represents the channel (a, b, c, d)
// The second parameter represents the device number
//
// In this example it's family 'd', device #2
mySwitch.switchOn('d', 2);
// Wait a second
delay(1000);
// Switch off
mySwitch.switchOff('d', 2);
// Wait another second
delay(1000);
}

View File

@ -0,0 +1,154 @@
/*
A simple RCSwitch/Ethernet/Webserver demo
https://github.com/sui77/rc-switch/
*/
#include <SPI.h>
#include <Ethernet.h>
#include <RCSwitch.h>
// Ethernet configuration
uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // MAC Address
uint8_t ip[] = { 192,168,0, 2 }; // IP Address
EthernetServer server(80); // Server Port 80
// RCSwitch configuration
RCSwitch mySwitch = RCSwitch();
int RCTransmissionPin = 7;
// More to do...
// You should also modify the processCommand() and
// httpResponseHome() functions to fit your needs.
/**
* Setup
*/
void setup() {
Ethernet.begin(mac, ip);
server.begin();
mySwitch.enableTransmit( RCTransmissionPin );
}
/**
* Loop
*/
void loop() {
char* command = httpServer();
}
/**
* Command dispatcher
*/
void processCommand(char* command) {
if (strcmp(command, "1-on") == 0) {
mySwitch.switchOn(1,1);
} else if (strcmp(command, "1-off") == 0) {
mySwitch.switchOff(1,1);
} else if (strcmp(command, "2-on") == 0) {
mySwitch.switchOn(1,2);
} else if (strcmp(command, "2-off") == 0) {
mySwitch.switchOff(1,2);
}
}
/**
* HTTP Response with homepage
*/
void httpResponseHome(EthernetClient c) {
c.println("HTTP/1.1 200 OK");
c.println("Content-Type: text/html");
c.println();
c.println("<html>");
c.println("<head>");
c.println( "<title>RCSwitch Webserver Demo</title>");
c.println( "<style>");
c.println( "body { font-family: Arial, sans-serif; font-size:12px; }");
c.println( "</style>");
c.println("</head>");
c.println("<body>");
c.println( "<h1>RCSwitch Webserver Demo</h1>");
c.println( "<ul>");
c.println( "<li><a href=\"./?1-on\">Switch #1 on</a></li>");
c.println( "<li><a href=\"./?1-off\">Switch #1 off</a></li>");
c.println( "</ul>");
c.println( "<ul>");
c.println( "<li><a href=\"./?2-on\">Switch #2 on</a></li>");
c.println( "<li><a href=\"./?2-off\">Switch #2 off</a></li>");
c.println( "</ul>");
c.println( "<hr>");
c.println( "<a href=\"https://github.com/sui77/rc-switch/\">https://github.com/sui77/rc-switch/</a>");
c.println("</body>");
c.println("</html>");
}
/**
* HTTP Redirect to homepage
*/
void httpResponseRedirect(EthernetClient c) {
c.println("HTTP/1.1 301 Found");
c.println("Location: /");
c.println();
}
/**
* HTTP Response 414 error
* Command must not be longer than 30 characters
**/
void httpResponse414(EthernetClient c) {
c.println("HTTP/1.1 414 Request URI too long");
c.println("Content-Type: text/plain");
c.println();
c.println("414 Request URI too long");
}
/**
* Process HTTP requests, parse first request header line and
* call processCommand with GET query string (everything after
* the ? question mark in the URL).
*/
char* httpServer() {
EthernetClient client = server.available();
if (client) {
char sReturnCommand[32];
int nCommandPos=-1;
sReturnCommand[0] = '\0';
while (client.connected()) {
if (client.available()) {
char c = client.read();
if ((c == '\n') || (c == ' ' && nCommandPos>-1)) {
sReturnCommand[nCommandPos] = '\0';
if (strcmp(sReturnCommand, "\0") == 0) {
httpResponseHome(client);
} else {
processCommand(sReturnCommand);
httpResponseRedirect(client);
}
break;
}
if (nCommandPos>-1) {
sReturnCommand[nCommandPos++] = c;
}
if (c == '?' && nCommandPos == -1) {
nCommandPos = 0;
}
}
if (nCommandPos > 30) {
httpResponse414(client);
sReturnCommand[0] = '\0';
break;
}
}
if (nCommandPos!=-1) {
sReturnCommand[nCommandPos] = '\0';
}
// give the web browser time to receive the data
delay(1);
client.stop();
return sReturnCommand;
}
return '\0';
}

View File

@ -0,0 +1,57 @@
#######################################
# Syntax Coloring Map For RCSwitch
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
RCSwitch KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
##########
#SENDS Begin
##########
switchOn KEYWORD2
switchOff KEYWORD2
sendTriState KEYWORD2
send KEYWORD2
##########
#SENDS End
##########
##########
#RECEIVE Begin
##########
enableReceive KEYWORD2
disableReceive KEYWORD2
available KEYWORD2
resetAvailable KEYWORD2
setReceiveTolerance KEYWORD2
getReceivedValue KEYWORD2
getReceivedBitlength KEYWORD2
getReceivedDelay KEYWORD2
getReceivedProtocol KEYWORD2
getReceivedRawdata KEYWORD2
##########
#RECEIVE End
##########
##########
#OTHERS Begin
##########
enableTransmit KEYWORD2
disableTransmit KEYWORD2
setPulseLength KEYWORD2
setProtocol KEYWORD2
setRepeatTransmit KEYWORD2
##########
#OTHERS End
##########
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -0,0 +1,21 @@
{
"name": "rc-switch",
"description": "Use your Arduino or Raspberry Pi to operate remote radio controlled devices",
"keywords": "rf, radio, wireless",
"authors":
{
"name": "Suat Ozgur"
},
"repository":
{
"type": "git",
"url": "https://github.com/sui77/rc-switch.git"
},
"version": "2.6.2",
"frameworks": [
"arduino",
"energia",
"wiringpi"
],
"platforms": "*"
}

View File

@ -0,0 +1,10 @@
name=rc-switch
version=2.6.2
author=sui77
maintainer=sui77,fingolfin <noreply@sui.li>
sentence=Operate 433/315Mhz devices.
paragraph=Use your Arduino, ESP8266/ESP32 or Raspberry Pi to operate remote radio controlled devices. This will most likely work with all popular low cost power outlet sockets.
category=Device Control
url=https://github.com/sui77/rc-switch
architectures=avr,esp8266,esp32
includes=RCSwitch.h

View File

@ -62,7 +62,10 @@ board_build.f_cpu = 80000000L
build_unflags = -Wall
build_flags =
-Wl,-Tesp8266.flash.1m0.ld
; if using esp8266 core 2.5.0 (stage) or up
; -Wl,-Tesp8266.flash.1m.ld -Wl,-Map,firmware.map
; if using esp8266 core < 2.5.0
-Wl,-Tesp8266.flash.1m0.ld -Wl,-Map,firmware.map
-mtarget-align
; -DUSE_CONFIG_OVERRIDE
; lwIP 1.4 (Default)

View File

@ -1,7 +1,37 @@
/* 6.2.1.15 20181012
/* 6.2.1.19 20181023
* Fix header file execution order by renaming user_config.h to my_user_config.h
* Fix invalid JSON floating point result from nan (Not a Number) and inf (Infinity) into null (#4147)
* Fix rule mqtt#connected trigger when mqtt is disabled (#4149)
* Initial release of RF transceiving using library RcSwitch (#2702)
*
* 6.2.1.18 20181019
* Add more API callbacks and document API.md
* Add support for La Crosse TX20 Anemometer (#2654, #3146)
* Add optional HX711 scale interface to web GUI demonstrating easy GUI plug-in
* Resize HX711 weight_item field from 16 bit to 32 bit
*
* 6.2.1.17 20181017
* Enable updated non-blocking PubSubClient as default MQTT client
* Update TasmotaModbus and TasmotaSerial libraries for support of serial 8N2 communication
* Add support for Pzem-003/017 DC Energy monitoring module (#3694)
* Change support for Pzem-014/016 AC Energy monitoring module (#3694)
* Rewrite Tuya Dimmer code
*
* 6.2.1.16 20181015
* Add TasmotaModbus library for very basic modbus wrapper for TasmotaSerial
* Change xsns_17_senseair.ino to use TasmotaModbus library
* Fix xnrg_05_pzem2.ino for PZEM-014/016 support using TasmotaModbus library (#3694)
* Fix RfRaw and SerialSend5 regression from 6.2.1.15 (#4072)
* Fix Sonoff Bridge RfRaw receive (#4080, #4085)
* Add support for Tuya Dimmer (#469, #4075)
* Fix possible wifi connection error (#4044, #4083)
* Update PubSubClient Mqtt library to non-blocking EspEasy version
*
* 6.2.1.15 20181012
* Fix Color Temperature slider functionality regression from 6.2.1.5 (#4037)
* Add auto reload of main web page to some web restarts
* Add whitespace removal from RfRaw and SerialSend5 (#4020)
* Add commands Reset 4 (reset to defaults but keep wifi params) and Reset 5 (as reset 4 and also erase flash) (#4061)
*
* 6.2.1.14 20181010
* Rewrite Webserver page handler for easier extension (thx to Adrian Scillato)

View File

@ -461,6 +461,23 @@
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
#define D_RESET_HX711 "Reset Scale"
#define D_CONFIGURE_HX711 "Configure Scale"
#define D_HX711_PARAMETERS "Scale parameters"
#define D_ITEM_WEIGHT "Item weight"
#define D_REFERENCE_WEIGHT "Reference weigth"
#define D_CALIBRATE "Calibrate"
#define D_CALIBRATION "Calibration"
//xsns_35_tx20.ino
#define D_TX20_WIND_DIRECTION "Wind Direction"
#define D_TX20_WIND_SPEED "Wind Speed"
#define D_TX20_WIND_SPEED_AVG "Wind Speed Avg"
#define D_TX20_WIND_SPEED_MAX "Wind Speed Max"
#define D_TX20_NORTH "N"
#define D_TX20_EAST "E"
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
// sonoff_template.h
#define D_SENSOR_NONE "Няма"
@ -482,8 +499,10 @@
#define D_SENSOR_IRRECV "IRrecv"
#define D_SENSOR_MHZ_RX "MHZ Rx"
#define D_SENSOR_MHZ_TX "MHZ Tx"
#define D_SENSOR_PZEM_RX "PZEM Rx"
#define D_SENSOR_PZEM_TX "PZEM Tx"
#define D_SENSOR_PZEM004_RX "PZEM004 Rx"
#define D_SENSOR_PZEM016_RX "PZEM016 Rx"
#define D_SENSOR_PZEM017_RX "PZEM017 Rx"
#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx"
#define D_SENSOR_SAIR_RX "SAir Rx"
#define D_SENSOR_SAIR_TX "SAir Tx"
#define D_SENSOR_SPI_CS "SPI CS"
@ -505,6 +524,9 @@
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv"
// Units
#define D_UNIT_AMPERE "A"
@ -513,6 +535,7 @@
#define D_UNIT_HOUR "h"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOOHM "kΩ"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -461,6 +461,23 @@
#define D_HX_CAL_REFERENCE "Vložte referenční zátěž"
#define D_HX_CAL_DONE "Zkalibrováno"
#define D_HX_CAL_FAIL "Chyba kalibrace"
#define D_RESET_HX711 "Reset váhy"
#define D_CONFIGURE_HX711 "Konfigurace váhy"
#define D_HX711_PARAMETERS "Parametry váhy"
#define D_ITEM_WEIGHT "Vlastní hmotnost"
#define D_REFERENCE_WEIGHT "Referenční hmotnost"
#define D_CALIBRATE "Kalibruj"
#define D_CALIBRATION "Kalibrace"
//xsns_35_tx20.ino
#define D_TX20_WIND_DIRECTION "Směr větru"
#define D_TX20_WIND_SPEED "Rychlost větru"
#define D_TX20_WIND_SPEED_AVG "Průměrná rychlost větru"
#define D_TX20_WIND_SPEED_MAX "Maximální rychlost větru"
#define D_TX20_NORTH "S"
#define D_TX20_EAST "V"
#define D_TX20_SOUTH "J"
#define D_TX20_WEST "Z"
// sonoff_template.h
#define D_SENSOR_NONE "Není"
@ -482,8 +499,10 @@
#define D_SENSOR_IRRECV "IRrecv"
#define D_SENSOR_MHZ_RX "MHZ Rx"
#define D_SENSOR_MHZ_TX "MHZ Tx"
#define D_SENSOR_PZEM_RX "PZEM Rx"
#define D_SENSOR_PZEM_TX "PZEM Tx"
#define D_SENSOR_PZEM004_RX "PZEM004 Rx"
#define D_SENSOR_PZEM016_RX "PZEM016 Rx"
#define D_SENSOR_PZEM017_RX "PZEM017 Rx"
#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx"
#define D_SENSOR_SAIR_RX "SAir Rx"
#define D_SENSOR_SAIR_TX "SAir Tx"
#define D_SENSOR_SPI_CS "SPI CS"
@ -505,6 +524,9 @@
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv"
// Units
#define D_UNIT_AMPERE "A"
@ -513,6 +535,7 @@
#define D_UNIT_HOUR "hod"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -461,6 +461,23 @@
#define D_HX_CAL_REFERENCE "Referenzgewicht auflegen"
#define D_HX_CAL_DONE "kalibriert"
#define D_HX_CAL_FAIL "Kalibrierung fehlgeschlagen"
#define D_RESET_HX711 "Tara"
#define D_CONFIGURE_HX711 "Tara Wert?"
#define D_HX711_PARAMETERS "Skala Parameter"
#define D_ITEM_WEIGHT "Wägegut Gewicht"
#define D_REFERENCE_WEIGHT "Referenz Gewicht"
#define D_CALIBRATE "kalibriert"
#define D_CALIBRATION "Kalibrierung"
//xsns_35_tx20.ino
#define D_TX20_WIND_DIRECTION "Wind Richtung"
#define D_TX20_WIND_SPEED "Windgeschwindigkeit"
#define D_TX20_WIND_SPEED_AVG "Ø Windgeschwindigkeit"
#define D_TX20_WIND_SPEED_MAX "max Windgeschwindigkeit"
#define D_TX20_NORTH "N"
#define D_TX20_EAST "O"
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
// sonoff_template.h
#define D_SENSOR_NONE "None"
@ -482,8 +499,10 @@
#define D_SENSOR_IRRECV "IRRecv"
#define D_SENSOR_MHZ_RX "MHZ Rx"
#define D_SENSOR_MHZ_TX "MHZ Tx"
#define D_SENSOR_PZEM_RX "PZEM Rx"
#define D_SENSOR_PZEM_TX "PZEM Tx"
#define D_SENSOR_PZEM004_RX "PZEM004 Rx"
#define D_SENSOR_PZEM016_RX "PZEM016 Rx"
#define D_SENSOR_PZEM017_RX "PZEM017 Rx"
#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx"
#define D_SENSOR_SAIR_RX "SAir Rx"
#define D_SENSOR_SAIR_TX "SAir Tx"
#define D_SENSOR_SPI_CS "SPI CS"
@ -505,6 +524,9 @@
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv"
// Units
#define D_UNIT_AMPERE "A"
@ -513,6 +535,7 @@
#define D_UNIT_HOUR "h"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -461,6 +461,23 @@
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
#define D_RESET_HX711 "Reset Scale"
#define D_CONFIGURE_HX711 "Configure Scale"
#define D_HX711_PARAMETERS "Scale parameters"
#define D_ITEM_WEIGHT "Item weight"
#define D_REFERENCE_WEIGHT "Reference weigth"
#define D_CALIBRATE "Calibrate"
#define D_CALIBRATION "Calibration"
//xsns_35_tx20.ino
#define D_TX20_WIND_DIRECTION "Wind Direction"
#define D_TX20_WIND_SPEED "Wind Speed"
#define D_TX20_WIND_SPEED_AVG "Wind Speed Avg"
#define D_TX20_WIND_SPEED_MAX "Wind Speed Max"
#define D_TX20_NORTH "N"
#define D_TX20_EAST "E"
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
// sonoff_template.h
#define D_SENSOR_NONE "Κανένας"
@ -482,8 +499,10 @@
#define D_SENSOR_IRRECV "IRrecv"
#define D_SENSOR_MHZ_RX "MHZ Rx"
#define D_SENSOR_MHZ_TX "MHZ Tx"
#define D_SENSOR_PZEM_RX "PZEM Rx"
#define D_SENSOR_PZEM_TX "PZEM Tx"
#define D_SENSOR_PZEM004_RX "PZEM004 Rx"
#define D_SENSOR_PZEM016_RX "PZEM016 Rx"
#define D_SENSOR_PZEM017_RX "PZEM017 Rx"
#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx"
#define D_SENSOR_SAIR_RX "SAir Rx"
#define D_SENSOR_SAIR_TX "SAir Tx"
#define D_SENSOR_SPI_CS "SPI CS"
@ -505,6 +524,9 @@
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv"
// Units
#define D_UNIT_AMPERE "A"
@ -513,6 +535,7 @@
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -461,6 +461,23 @@
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
#define D_RESET_HX711 "Reset Scale"
#define D_CONFIGURE_HX711 "Configure Scale"
#define D_HX711_PARAMETERS "Scale parameters"
#define D_ITEM_WEIGHT "Item weight"
#define D_REFERENCE_WEIGHT "Reference weigth"
#define D_CALIBRATE "Calibrate"
#define D_CALIBRATION "Calibration"
//xsns_35_tx20.ino
#define D_TX20_WIND_DIRECTION "Wind Direction"
#define D_TX20_WIND_SPEED "Wind Speed"
#define D_TX20_WIND_SPEED_AVG "Wind Speed Avg"
#define D_TX20_WIND_SPEED_MAX "Wind Speed Max"
#define D_TX20_NORTH "N"
#define D_TX20_EAST "E"
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
// sonoff_template.h
#define D_SENSOR_NONE "None"
@ -482,8 +499,10 @@
#define D_SENSOR_IRRECV "IRrecv"
#define D_SENSOR_MHZ_RX "MHZ Rx"
#define D_SENSOR_MHZ_TX "MHZ Tx"
#define D_SENSOR_PZEM_RX "PZEM Rx"
#define D_SENSOR_PZEM_TX "PZEM Tx"
#define D_SENSOR_PZEM004_RX "PZEM004 Rx"
#define D_SENSOR_PZEM016_RX "PZEM016 Rx"
#define D_SENSOR_PZEM017_RX "PZEM017 Rx"
#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx"
#define D_SENSOR_SAIR_RX "SAir Rx"
#define D_SENSOR_SAIR_TX "SAir Tx"
#define D_SENSOR_SPI_CS "SPI CS"
@ -505,6 +524,9 @@
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv"
// Units
#define D_UNIT_AMPERE "A"
@ -513,6 +535,7 @@
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

Some files were not shown because too many files have changed in this diff Show More