mirror of https://github.com/arendst/Tasmota.git
Merge branch 'arendst/development' into development
This commit is contained in:
commit
d06c0c2636
|
@ -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 |
|
|
@ -55,7 +55,7 @@ See [Tasmota ESP/Arduino library version related issues](https://github.com/aren
|
||||||
| USE_SUNRISE | - | - | x | x | x |
|
| USE_SUNRISE | - | - | x | x | x |
|
||||||
| USE_RULES | - | - | 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_DS18B20 | - | - | - | - | - | Single sensor
|
||||||
| USE_DS18x20 | - | x | x | x | x | Multiple sensors
|
| USE_DS18x20 | - | x | x | x | x | Multiple sensors
|
||||||
| USE_DS18x20_LEGACY | - | - | - | - | - | 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_LM75AD | - | - | x | x | x |
|
||||||
| USE_APDS9960 | - | - | - | - | - |
|
| USE_APDS9960 | - | - | - | - | - |
|
||||||
| USE_MCP230xx | - | - | - | - | - |
|
| USE_MCP230xx | - | - | - | - | - |
|
||||||
|
| USE_PCA9685 | - | - | - | - | - |
|
||||||
| USE_MPR121 | - | - | - | - | - |
|
| USE_MPR121 | - | - | - | - | - |
|
||||||
| USE_CCS811 | - | - | - | - | - |
|
| USE_CCS811 | - | - | - | - | - |
|
||||||
| USE_MPU6050 | - | - | - | - | - |
|
| USE_MPU6050 | - | - | - | - | - |
|
||||||
|
| USE_DS3231 | - | - | - | - | - |
|
||||||
| | | | | | |
|
| | | | | | |
|
||||||
| Feature or Sensor | minimal | classic | sonoff | knx | sensors |
|
| Feature or Sensor | minimal | classic | sonoff | knx | sensors |
|
||||||
| USE_SPI | - | - | - | - | - |
|
| USE_SPI | - | - | - | - | - |
|
||||||
|
@ -90,9 +92,13 @@ See [Tasmota ESP/Arduino library version related issues](https://github.com/aren
|
||||||
| USE_PMS5003 | - | - | x | x | x |
|
| USE_PMS5003 | - | - | x | x | x |
|
||||||
| USE_NOVA_SDS | - | - | x | x | x |
|
| USE_NOVA_SDS | - | - | x | x | x |
|
||||||
| USE_PZEM004T | - | - | 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_SERIAL_BRIDGE | - | - | x | x | x |
|
||||||
| USE_SDM120 | - | - | - | - | x |
|
| USE_SDM120 | - | - | - | - | x |
|
||||||
| USE_SDM630 | - | - | - | - | x |
|
| USE_SDM630 | - | - | - | - | x |
|
||||||
|
| USE_MP3_PLAYER | - | - | - | - | - |
|
||||||
| USE_IR_REMOTE | - | - | x | x | x |
|
| USE_IR_REMOTE | - | - | x | x | x |
|
||||||
| USE_IR_HVAC | - | - | - | - | x |
|
| USE_IR_HVAC | - | - | - | - | x |
|
||||||
| USE_IR_RECEIVE | - | - | x | x | 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_ARILUX_RF | - | - | x | x | x |
|
||||||
| USE_SR04 | - | - | x | x | x |
|
| USE_SR04 | - | - | x | x | x |
|
||||||
| USE_TM1638 | - | - | - | - | - |
|
| USE_TM1638 | - | - | - | - | - |
|
||||||
|
| USE_HX711 | - | - | x | x | x |
|
||||||
| USE_RF_FLASH | - | - | 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
|
## Changelog
|
||||||
Version 6.2.1 20180905
|
Version 6.2.1 20180905
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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?");
|
|
||||||
}
|
|
|
@ -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?");
|
|
||||||
}
|
|
|
@ -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"
|
|
||||||
}
|
|
|
@ -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=*
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
|
@ -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")
|
|
|
@ -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()
|
|
|
@ -38,6 +38,14 @@ long lastMsg = 0;
|
||||||
char msg[50];
|
char msg[50];
|
||||||
int value = 0;
|
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() {
|
void setup_wifi() {
|
||||||
|
|
||||||
delay(10);
|
delay(10);
|
||||||
|
@ -53,8 +61,6 @@ void setup_wifi() {
|
||||||
Serial.print(".");
|
Serial.print(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
randomSeed(micros());
|
|
||||||
|
|
||||||
Serial.println("");
|
Serial.println("");
|
||||||
Serial.println("WiFi connected");
|
Serial.println("WiFi connected");
|
||||||
Serial.println("IP address: ");
|
Serial.println("IP address: ");
|
||||||
|
@ -85,11 +91,8 @@ void reconnect() {
|
||||||
// Loop until we're reconnected
|
// Loop until we're reconnected
|
||||||
while (!client.connected()) {
|
while (!client.connected()) {
|
||||||
Serial.print("Attempting MQTT connection...");
|
Serial.print("Attempting MQTT connection...");
|
||||||
// Create a random client ID
|
|
||||||
String clientId = "ESP8266Client-";
|
|
||||||
clientId += String(random(0xffff), HEX);
|
|
||||||
// Attempt to connect
|
// Attempt to connect
|
||||||
if (client.connect(clientId.c_str())) {
|
if (client.connect("ESP8266Client")) {
|
||||||
Serial.println("connected");
|
Serial.println("connected");
|
||||||
// Once connected, publish an announcement...
|
// Once connected, publish an announcement...
|
||||||
client.publish("outTopic", "hello world");
|
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() {
|
void loop() {
|
||||||
|
|
||||||
if (!client.connected()) {
|
if (!client.connected()) {
|
|
@ -117,8 +117,8 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
|
||||||
if (!connected()) {
|
if (!connected()) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if (domain != NULL) {
|
if (domain.length() != 0) {
|
||||||
result = _client->connect(this->domain, this->port);
|
result = _client->connect(this->domain.c_str(), this->port);
|
||||||
} else {
|
} else {
|
||||||
result = _client->connect(this->ip, this->port);
|
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) {
|
boolean PubSubClient::readByte(uint8_t * result) {
|
||||||
uint32_t previousMillis = millis();
|
uint32_t previousMillis = millis();
|
||||||
while(!_client->available()) {
|
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();
|
uint32_t currentMillis = millis();
|
||||||
if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
|
if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
|
||||||
return false;
|
return false;
|
||||||
|
@ -241,11 +241,17 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
|
||||||
uint8_t start = 0;
|
uint8_t start = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
if (len == 6) {
|
||||||
|
// Invalid remaining length encoding - kill the connection
|
||||||
|
_state = MQTT_DISCONNECTED;
|
||||||
|
_client->stop();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if(!readByte(&digit)) return 0;
|
if(!readByte(&digit)) return 0;
|
||||||
buffer[len++] = digit;
|
buffer[len++] = digit;
|
||||||
length += (digit & 127) * multiplier;
|
length += (digit & 127) * multiplier;
|
||||||
multiplier *= 128;
|
multiplier *= 128;
|
||||||
} while ((digit & 128) != 0);
|
} while ((digit & 128) != 0 && len < (MQTT_MAX_PACKET_SIZE -2));
|
||||||
*lengthLength = len-1;
|
*lengthLength = len-1;
|
||||||
|
|
||||||
if (isPublish) {
|
if (isPublish) {
|
||||||
|
@ -336,6 +342,9 @@ boolean PubSubClient::loop() {
|
||||||
} else if (type == MQTTPINGRESP) {
|
} else if (type == MQTTPINGRESP) {
|
||||||
pingOutstanding = false;
|
pingOutstanding = false;
|
||||||
}
|
}
|
||||||
|
} else if (!connected()) {
|
||||||
|
// readPacket has closed the connection
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -419,7 +428,7 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig
|
||||||
|
|
||||||
lastOutActivity = millis();
|
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) {
|
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) {
|
boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
|
||||||
if (qos < 0 || qos > 1) {
|
if (qos > 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
|
if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
|
||||||
|
@ -514,9 +523,12 @@ boolean PubSubClient::unsubscribe(const char* topic) {
|
||||||
void PubSubClient::disconnect() {
|
void PubSubClient::disconnect() {
|
||||||
buffer[0] = MQTTDISCONNECT;
|
buffer[0] = MQTTDISCONNECT;
|
||||||
buffer[1] = 0;
|
buffer[1] = 0;
|
||||||
_client->write(buffer,2);
|
if (_client != NULL) {
|
||||||
|
_client->write(buffer,2);
|
||||||
|
_client->flush();
|
||||||
|
_client->stop();
|
||||||
|
}
|
||||||
_state = MQTT_DISCONNECTED;
|
_state = MQTT_DISCONNECTED;
|
||||||
_client->stop();
|
|
||||||
lastInActivity = lastOutActivity = millis();
|
lastInActivity = lastOutActivity = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,7 +536,7 @@ uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t po
|
||||||
const char* idp = string;
|
const char* idp = string;
|
||||||
uint16_t i = 0;
|
uint16_t i = 0;
|
||||||
pos += 2;
|
pos += 2;
|
||||||
while (*idp) {
|
while (*idp && pos < (MQTT_MAX_PACKET_SIZE - 2)) {
|
||||||
buf[pos++] = *idp++;
|
buf[pos++] = *idp++;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -559,7 +571,7 @@ PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) {
|
||||||
PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) {
|
PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) {
|
||||||
this->ip = ip;
|
this->ip = ip;
|
||||||
this->port = port;
|
this->port = port;
|
||||||
this->domain = NULL;
|
this->domain = "";
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,13 +24,13 @@
|
||||||
// MQTT_MAX_PACKET_SIZE : Maximum packet size
|
// MQTT_MAX_PACKET_SIZE : Maximum packet size
|
||||||
#ifndef MQTT_MAX_PACKET_SIZE
|
#ifndef MQTT_MAX_PACKET_SIZE
|
||||||
//#define MQTT_MAX_PACKET_SIZE 128
|
//#define MQTT_MAX_PACKET_SIZE 128
|
||||||
//#define MQTT_MAX_PACKET_SIZE 512 // Tasmota
|
|
||||||
#define MQTT_MAX_PACKET_SIZE 1000 // Tasmota v5.11.1c
|
#define MQTT_MAX_PACKET_SIZE 1000 // Tasmota v5.11.1c
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// MQTT_KEEPALIVE : keepAlive interval in Seconds
|
// MQTT_KEEPALIVE : keepAlive interval in Seconds
|
||||||
|
// Keepalive timeout for default MQTT Broker is 10s
|
||||||
#ifndef MQTT_KEEPALIVE
|
#ifndef MQTT_KEEPALIVE
|
||||||
#define MQTT_KEEPALIVE 15
|
#define MQTT_KEEPALIVE 10
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
|
// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
#define MQTTQOS1 (1 << 1)
|
#define MQTTQOS1 (1 << 1)
|
||||||
#define MQTTQOS2 (2 << 1)
|
#define MQTTQOS2 (2 << 1)
|
||||||
|
|
||||||
#ifdef ESP8266
|
#if defined(ESP8266) || defined(ESP32)
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
|
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
|
||||||
#else
|
#else
|
||||||
|
@ -97,7 +97,7 @@ private:
|
||||||
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
|
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
|
||||||
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
|
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
|
||||||
IPAddress ip;
|
IPAddress ip;
|
||||||
const char* domain;
|
String domain;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
Stream* stream;
|
Stream* stream;
|
||||||
int _state;
|
int _state;
|
||||||
|
@ -116,6 +116,7 @@ public:
|
||||||
PubSubClient(const char*, uint16_t, Client& client, Stream&);
|
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);
|
||||||
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
|
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
|
||||||
|
virtual ~PubSubClient() {}
|
||||||
|
|
||||||
PubSubClient& setServer(IPAddress ip, uint16_t port);
|
PubSubClient& setServer(IPAddress ip, uint16_t port);
|
||||||
PubSubClient& setServer(uint8_t * ip, uint16_t port);
|
PubSubClient& setServer(uint8_t * ip, uint16_t port);
|
|
@ -133,23 +133,6 @@ int test_connect_accepts_username_no_password() {
|
||||||
|
|
||||||
END_IT
|
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() {
|
int test_connect_ignores_password_no_username() {
|
||||||
IT("ignores a password but no username");
|
IT("ignores a password but no username");
|
|
@ -2,13 +2,9 @@
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
|
||||||
Buffer::Buffer() {
|
Buffer::Buffer() {
|
||||||
this->pos = 0;
|
|
||||||
this->length = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::Buffer(uint8_t* buf, size_t size) {
|
Buffer::Buffer(uint8_t* buf, size_t size) {
|
||||||
this->pos = 0;
|
|
||||||
this->length = 0;
|
|
||||||
this->add(buf,size);
|
this->add(buf,size);
|
||||||
}
|
}
|
||||||
bool Buffer::available() {
|
bool Buffer::available() {
|
|
@ -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")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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()
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,33 +1,26 @@
|
||||||
#######################################
|
#######################################
|
||||||
# Syntax Coloring Map For Ultrasound
|
# Syntax Coloring Map for TasmotaModbus
|
||||||
|
# (esp8266)
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Datatypes (KEYWORD1)
|
# Datatypes (KEYWORD1)
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
AsyncUDP KEYWORD1
|
TasmotaModbus KEYWORD1
|
||||||
AsyncUDPPacket KEYWORD1
|
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Methods and Functions (KEYWORD2)
|
# Methods and Functions (KEYWORD2)
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
connect KEYWORD2
|
Begin KEYWORD2
|
||||||
connected KEYWORD2
|
Send KEYWORD2
|
||||||
listen KEYWORD2
|
ReceiveReady KEYWORD2
|
||||||
listenMulticast KEYWORD2
|
ReceiveBuffer KEYWORD2
|
||||||
close KEYWORD2
|
Receive16BitRegister KEYWORD2
|
||||||
write KEYWORD2
|
Receive32BitRegister KEYWORD2
|
||||||
broadcast KEYWORD2
|
|
||||||
onPacket KEYWORD2
|
|
||||||
data KEYWORD2
|
|
||||||
length KEYWORD2
|
|
||||||
localIP KEYWORD2
|
|
||||||
localPort KEYWORD2
|
|
||||||
remoteIP KEYWORD2
|
|
||||||
remotePort KEYWORD2
|
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Constants (LITERAL1)
|
# Constants (LITERAL1)
|
||||||
#######################################
|
#######################################
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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.
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "TasmotaSerial",
|
"name": "TasmotaSerial",
|
||||||
"version": "2.0.0",
|
"version": "2.1.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"serial", "io", "TasmotaSerial"
|
"serial", "io", "TasmotaSerial"
|
||||||
],
|
],
|
|
@ -1,5 +1,5 @@
|
||||||
name=TasmotaSerial
|
name=TasmotaSerial
|
||||||
version=2.0.0
|
version=2.1.0
|
||||||
author=Theo Arends
|
author=Theo Arends
|
||||||
maintainer=Theo Arends <theo@arends.com>
|
maintainer=Theo Arends <theo@arends.com>
|
||||||
sentence=Implementation of software serial with hardware serial fallback for ESP8266.
|
sentence=Implementation of software serial with hardware serial fallback for ESP8266.
|
|
@ -80,6 +80,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, bool hardware_fa
|
||||||
{
|
{
|
||||||
m_valid = false;
|
m_valid = false;
|
||||||
m_hardserial = 0;
|
m_hardserial = 0;
|
||||||
|
m_stop_bits = 1;
|
||||||
if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) {
|
if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -106,15 +107,33 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, bool hardware_fa
|
||||||
m_valid = true;
|
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)
|
bool TasmotaSerial::isValidGPIOpin(int pin)
|
||||||
{
|
{
|
||||||
return (pin >= -1 && pin <= 5) || (pin >= 12 && pin <= 15);
|
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) {
|
if (m_hardserial) {
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
Serial.begin(speed, SERIAL_8N1);
|
if (2 == m_stop_bits) {
|
||||||
|
Serial.begin(speed, SERIAL_8N2);
|
||||||
|
} else {
|
||||||
|
Serial.begin(speed, SERIAL_8N1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use getCycleCount() loop to get as exact timing as possible
|
// Use getCycleCount() loop to get as exact timing as possible
|
||||||
m_bit_time = ESP.getCpuFreqMHz() *1000000 /speed;
|
m_bit_time = ESP.getCpuFreqMHz() *1000000 /speed;
|
||||||
|
@ -195,9 +214,11 @@ size_t TasmotaSerial::write(uint8_t b)
|
||||||
TM_SERIAL_WAIT;
|
TM_SERIAL_WAIT;
|
||||||
b >>= 1;
|
b >>= 1;
|
||||||
}
|
}
|
||||||
// Stop bit
|
// Stop bit(s)
|
||||||
digitalWrite(m_tx_pin, HIGH);
|
for (int i = 0; i < m_stop_bits; i++) {
|
||||||
TM_SERIAL_WAIT;
|
digitalWrite(m_tx_pin, HIGH);
|
||||||
|
TM_SERIAL_WAIT;
|
||||||
|
}
|
||||||
if (m_high_speed) sei();
|
if (m_high_speed) sei();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -220,8 +241,12 @@ void TasmotaSerial::rxRead()
|
||||||
rec >>= 1;
|
rec >>= 1;
|
||||||
if (digitalRead(m_rx_pin)) rec |= 0x80;
|
if (digitalRead(m_rx_pin)) rec |= 0x80;
|
||||||
}
|
}
|
||||||
// Stop bit
|
// Stop bit(s)
|
||||||
TM_SERIAL_WAIT;
|
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
|
// Store the received value in the buffer unless we have an overflow
|
||||||
int next = (m_in_pos+1) % TM_SERIAL_BUFFER_SIZE;
|
int next = (m_in_pos+1) % TM_SERIAL_BUFFER_SIZE;
|
||||||
if (next != (int)m_out_pos) {
|
if (next != (int)m_out_pos) {
|
|
@ -33,12 +33,15 @@
|
||||||
#define TM_SERIAL_USE_IRAM // Enable to use iram (+368 bytes)
|
#define TM_SERIAL_USE_IRAM // Enable to use iram (+368 bytes)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <Stream.h>
|
#include <Stream.h>
|
||||||
|
|
||||||
class TasmotaSerial : public Stream {
|
class TasmotaSerial : public Stream {
|
||||||
public:
|
public:
|
||||||
TasmotaSerial(int receive_pin, int transmit_pin, bool hardware_fallback = false);
|
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 begin();
|
||||||
bool hardwareSerial();
|
bool hardwareSerial();
|
||||||
int peek();
|
int peek();
|
||||||
|
@ -62,6 +65,7 @@ class TasmotaSerial : public Stream {
|
||||||
bool m_high_speed;
|
bool m_high_speed;
|
||||||
int m_rx_pin;
|
int m_rx_pin;
|
||||||
int m_tx_pin;
|
int m_tx_pin;
|
||||||
|
int m_stop_bits;
|
||||||
unsigned long m_bit_time;
|
unsigned long m_bit_time;
|
||||||
unsigned int m_in_pos;
|
unsigned int m_in_pos;
|
||||||
unsigned int m_out_pos;
|
unsigned int m_out_pos;
|
|
@ -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
|
|
@ -77,13 +77,10 @@ void ESPKNXIP::send(address_t const &receiver, knx_command_type_t ct, uint8_t da
|
||||||
DEBUG_PRINTLN(F(""));
|
DEBUG_PRINTLN(F(""));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ASYNC_UDP
|
|
||||||
udp.writeTo(buf, len, MULTICAST_IP, MULTICAST_PORT);
|
|
||||||
#else
|
|
||||||
udp.beginPacketMulticast(MULTICAST_IP, MULTICAST_PORT, WiFi.localIP());
|
udp.beginPacketMulticast(MULTICAST_IP, MULTICAST_PORT, WiFi.localIP());
|
||||||
udp.write(buf, len);
|
udp.write(buf, len);
|
||||||
udp.endPacket();
|
udp.endPacket();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESPKNXIP::send_1bit(address_t const &receiver, knx_command_type_t ct, uint8_t bit)
|
void ESPKNXIP::send_1bit(address_t const &receiver, knx_command_type_t ct, uint8_t bit)
|
||||||
|
|
|
@ -95,13 +95,7 @@ void ESPKNXIP::__start()
|
||||||
#endif
|
#endif
|
||||||
server->begin();
|
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);
|
udp.beginMulticast(WiFi.localIP(), MULTICAST_IP, MULTICAST_PORT);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESPKNXIP::save_to_eeprom()
|
void ESPKNXIP::save_to_eeprom()
|
||||||
|
@ -516,9 +510,7 @@ feedback_id_t ESPKNXIP::feedback_register_action(String name, feedback_action_fp
|
||||||
|
|
||||||
void ESPKNXIP::loop()
|
void ESPKNXIP::loop()
|
||||||
{
|
{
|
||||||
#ifndef USE_ASYNC_UDP
|
|
||||||
__loop_knx();
|
__loop_knx();
|
||||||
#endif
|
|
||||||
if (server != nullptr)
|
if (server != nullptr)
|
||||||
{
|
{
|
||||||
__loop_webserver();
|
__loop_webserver();
|
||||||
|
@ -530,15 +522,9 @@ void ESPKNXIP::__loop_webserver()
|
||||||
server->handleClient();
|
server->handleClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_ASYNC_UDP
|
|
||||||
void ESPKNXIP::__loop_knx(AsyncUDPPacket &packet)
|
|
||||||
{
|
|
||||||
size_t read = packet.length();
|
|
||||||
#else
|
|
||||||
void ESPKNXIP::__loop_knx()
|
void ESPKNXIP::__loop_knx()
|
||||||
{
|
{
|
||||||
int read = udp.parsePacket();
|
int read = udp.parsePacket();
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!read)
|
if (!read)
|
||||||
{
|
{
|
||||||
|
@ -548,23 +534,15 @@ void ESPKNXIP::__loop_knx()
|
||||||
DEBUG_PRINT(F("LEN: "));
|
DEBUG_PRINT(F("LEN: "));
|
||||||
DEBUG_PRINTLN(read);
|
DEBUG_PRINTLN(read);
|
||||||
|
|
||||||
#ifdef USE_ASYNC_UDP
|
|
||||||
uint8_t *buf = packet.data();
|
|
||||||
#else
|
|
||||||
uint8_t buf[read];
|
uint8_t buf[read];
|
||||||
udp.read(buf, read);
|
udp.read(buf, read);
|
||||||
udp.flush();
|
udp.flush();
|
||||||
#endif
|
|
||||||
|
|
||||||
DEBUG_PRINT(F("Got packet:"));
|
DEBUG_PRINT(F("Got packet:"));
|
||||||
|
|
||||||
#ifdef ESP_KNX_DEBUG
|
#ifdef ESP_KNX_DEBUG
|
||||||
|
|
||||||
#ifdef USE_ASYNC_UDP
|
|
||||||
for (size_t i = 0; i < read; ++i)
|
|
||||||
#else
|
|
||||||
for (int i = 0; i < read; ++i)
|
for (int i = 0; i < read; ++i)
|
||||||
#endif
|
|
||||||
|
|
||||||
{
|
{
|
||||||
DEBUG_PRINT(F(" 0x"));
|
DEBUG_PRINT(F(" 0x"));
|
||||||
|
|
|
@ -45,18 +45,7 @@
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include <EEPROM.h>
|
#include <EEPROM.h>
|
||||||
#include <ESP8266WiFi.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>
|
#include <WiFiUdp.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ESP8266WebServer.h>
|
#include <ESP8266WebServer.h>
|
||||||
|
|
||||||
#include "DPT.h"
|
#include "DPT.h"
|
||||||
|
@ -529,11 +518,7 @@ class ESPKNXIP {
|
||||||
private:
|
private:
|
||||||
void __start();
|
void __start();
|
||||||
|
|
||||||
#ifdef USE_ASYNC_UDP
|
|
||||||
void __loop_knx(AsyncUDPPacket &packet);
|
|
||||||
#else
|
|
||||||
void __loop_knx();
|
void __loop_knx();
|
||||||
#endif
|
|
||||||
|
|
||||||
// Webserver functions
|
// Webserver functions
|
||||||
void __loop_webserver();
|
void __loop_webserver();
|
||||||
|
@ -569,11 +554,7 @@ class ESPKNXIP {
|
||||||
ESP8266WebServer *server;
|
ESP8266WebServer *server;
|
||||||
address_t physaddr;
|
address_t physaddr;
|
||||||
|
|
||||||
#ifdef USE_ASYNC_UDP
|
|
||||||
AsyncUDP udp;
|
|
||||||
#else
|
|
||||||
WiFiUDP udp;
|
WiFiUDP udp;
|
||||||
#endif
|
|
||||||
|
|
||||||
callback_assignment_id_t registered_callback_assignments;
|
callback_assignment_id_t registered_callback_assignments;
|
||||||
callback_assignment_id_t free_callback_assignment_slots;
|
callback_assignment_id_t free_callback_assignment_slots;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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';
|
||||||
|
}
|
|
@ -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)
|
||||||
|
#######################################
|
|
@ -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": "*"
|
||||||
|
}
|
|
@ -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
|
|
@ -62,7 +62,10 @@ board_build.f_cpu = 80000000L
|
||||||
build_unflags = -Wall
|
build_unflags = -Wall
|
||||||
|
|
||||||
build_flags =
|
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
|
-mtarget-align
|
||||||
; -DUSE_CONFIG_OVERRIDE
|
; -DUSE_CONFIG_OVERRIDE
|
||||||
; lwIP 1.4 (Default)
|
; lwIP 1.4 (Default)
|
||||||
|
|
|
@ -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)
|
* Fix Color Temperature slider functionality regression from 6.2.1.5 (#4037)
|
||||||
* Add auto reload of main web page to some web restarts
|
* Add auto reload of main web page to some web restarts
|
||||||
* Add whitespace removal from RfRaw and SerialSend5 (#4020)
|
* 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
|
* 6.2.1.14 20181010
|
||||||
* Rewrite Webserver page handler for easier extension (thx to Adrian Scillato)
|
* Rewrite Webserver page handler for easier extension (thx to Adrian Scillato)
|
||||||
|
|
|
@ -461,6 +461,23 @@
|
||||||
#define D_HX_CAL_REFERENCE "Load reference weigth"
|
#define D_HX_CAL_REFERENCE "Load reference weigth"
|
||||||
#define D_HX_CAL_DONE "Calibrated"
|
#define D_HX_CAL_DONE "Calibrated"
|
||||||
#define D_HX_CAL_FAIL "Calibration failed"
|
#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
|
// sonoff_template.h
|
||||||
#define D_SENSOR_NONE "Няма"
|
#define D_SENSOR_NONE "Няма"
|
||||||
|
@ -482,8 +499,10 @@
|
||||||
#define D_SENSOR_IRRECV "IRrecv"
|
#define D_SENSOR_IRRECV "IRrecv"
|
||||||
#define D_SENSOR_MHZ_RX "MHZ Rx"
|
#define D_SENSOR_MHZ_RX "MHZ Rx"
|
||||||
#define D_SENSOR_MHZ_TX "MHZ Tx"
|
#define D_SENSOR_MHZ_TX "MHZ Tx"
|
||||||
#define D_SENSOR_PZEM_RX "PZEM Rx"
|
#define D_SENSOR_PZEM004_RX "PZEM004 Rx"
|
||||||
#define D_SENSOR_PZEM_TX "PZEM Tx"
|
#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_RX "SAir Rx"
|
||||||
#define D_SENSOR_SAIR_TX "SAir Tx"
|
#define D_SENSOR_SAIR_TX "SAir Tx"
|
||||||
#define D_SENSOR_SPI_CS "SPI CS"
|
#define D_SENSOR_SPI_CS "SPI CS"
|
||||||
|
@ -505,6 +524,9 @@
|
||||||
#define D_SENSOR_TM1638_STB "TM16 STB"
|
#define D_SENSOR_TM1638_STB "TM16 STB"
|
||||||
#define D_SENSOR_HX711_SCK "HX711 SCK"
|
#define D_SENSOR_HX711_SCK "HX711 SCK"
|
||||||
#define D_SENSOR_HX711_DAT "HX711 DAT"
|
#define D_SENSOR_HX711_DAT "HX711 DAT"
|
||||||
|
#define D_SENSOR_TX20_TX "TX20"
|
||||||
|
#define D_SENSOR_RFSEND "RFSend"
|
||||||
|
#define D_SENSOR_RFRECV "RFrecv"
|
||||||
|
|
||||||
// Units
|
// Units
|
||||||
#define D_UNIT_AMPERE "A"
|
#define D_UNIT_AMPERE "A"
|
||||||
|
@ -513,6 +535,7 @@
|
||||||
#define D_UNIT_HOUR "h"
|
#define D_UNIT_HOUR "h"
|
||||||
#define D_UNIT_KILOGRAM "kg"
|
#define D_UNIT_KILOGRAM "kg"
|
||||||
#define D_UNIT_INCREMENTS "inc"
|
#define D_UNIT_INCREMENTS "inc"
|
||||||
|
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
|
||||||
#define D_UNIT_KILOOHM "kΩ"
|
#define D_UNIT_KILOOHM "kΩ"
|
||||||
#define D_UNIT_KILOWATTHOUR "kWh"
|
#define D_UNIT_KILOWATTHOUR "kWh"
|
||||||
#define D_UNIT_LUX "lx"
|
#define D_UNIT_LUX "lx"
|
||||||
|
|
|
@ -461,6 +461,23 @@
|
||||||
#define D_HX_CAL_REFERENCE "Vložte referenční zátěž"
|
#define D_HX_CAL_REFERENCE "Vložte referenční zátěž"
|
||||||
#define D_HX_CAL_DONE "Zkalibrováno"
|
#define D_HX_CAL_DONE "Zkalibrováno"
|
||||||
#define D_HX_CAL_FAIL "Chyba kalibrace"
|
#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
|
// sonoff_template.h
|
||||||
#define D_SENSOR_NONE "Není"
|
#define D_SENSOR_NONE "Není"
|
||||||
|
@ -482,8 +499,10 @@
|
||||||
#define D_SENSOR_IRRECV "IRrecv"
|
#define D_SENSOR_IRRECV "IRrecv"
|
||||||
#define D_SENSOR_MHZ_RX "MHZ Rx"
|
#define D_SENSOR_MHZ_RX "MHZ Rx"
|
||||||
#define D_SENSOR_MHZ_TX "MHZ Tx"
|
#define D_SENSOR_MHZ_TX "MHZ Tx"
|
||||||
#define D_SENSOR_PZEM_RX "PZEM Rx"
|
#define D_SENSOR_PZEM004_RX "PZEM004 Rx"
|
||||||
#define D_SENSOR_PZEM_TX "PZEM Tx"
|
#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_RX "SAir Rx"
|
||||||
#define D_SENSOR_SAIR_TX "SAir Tx"
|
#define D_SENSOR_SAIR_TX "SAir Tx"
|
||||||
#define D_SENSOR_SPI_CS "SPI CS"
|
#define D_SENSOR_SPI_CS "SPI CS"
|
||||||
|
@ -505,6 +524,9 @@
|
||||||
#define D_SENSOR_TM1638_STB "TM16 STB"
|
#define D_SENSOR_TM1638_STB "TM16 STB"
|
||||||
#define D_SENSOR_HX711_SCK "HX711 SCK"
|
#define D_SENSOR_HX711_SCK "HX711 SCK"
|
||||||
#define D_SENSOR_HX711_DAT "HX711 DAT"
|
#define D_SENSOR_HX711_DAT "HX711 DAT"
|
||||||
|
#define D_SENSOR_TX20_TX "TX20"
|
||||||
|
#define D_SENSOR_RFSEND "RFSend"
|
||||||
|
#define D_SENSOR_RFRECV "RFrecv"
|
||||||
|
|
||||||
// Units
|
// Units
|
||||||
#define D_UNIT_AMPERE "A"
|
#define D_UNIT_AMPERE "A"
|
||||||
|
@ -513,6 +535,7 @@
|
||||||
#define D_UNIT_HOUR "hod"
|
#define D_UNIT_HOUR "hod"
|
||||||
#define D_UNIT_KILOGRAM "kg"
|
#define D_UNIT_KILOGRAM "kg"
|
||||||
#define D_UNIT_INCREMENTS "inc"
|
#define D_UNIT_INCREMENTS "inc"
|
||||||
|
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
|
||||||
#define D_UNIT_KILOOHM "kOhm"
|
#define D_UNIT_KILOOHM "kOhm"
|
||||||
#define D_UNIT_KILOWATTHOUR "kWh"
|
#define D_UNIT_KILOWATTHOUR "kWh"
|
||||||
#define D_UNIT_LUX "lx"
|
#define D_UNIT_LUX "lx"
|
||||||
|
|
|
@ -461,6 +461,23 @@
|
||||||
#define D_HX_CAL_REFERENCE "Referenzgewicht auflegen"
|
#define D_HX_CAL_REFERENCE "Referenzgewicht auflegen"
|
||||||
#define D_HX_CAL_DONE "kalibriert"
|
#define D_HX_CAL_DONE "kalibriert"
|
||||||
#define D_HX_CAL_FAIL "Kalibrierung fehlgeschlagen"
|
#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
|
// sonoff_template.h
|
||||||
#define D_SENSOR_NONE "None"
|
#define D_SENSOR_NONE "None"
|
||||||
|
@ -482,8 +499,10 @@
|
||||||
#define D_SENSOR_IRRECV "IRRecv"
|
#define D_SENSOR_IRRECV "IRRecv"
|
||||||
#define D_SENSOR_MHZ_RX "MHZ Rx"
|
#define D_SENSOR_MHZ_RX "MHZ Rx"
|
||||||
#define D_SENSOR_MHZ_TX "MHZ Tx"
|
#define D_SENSOR_MHZ_TX "MHZ Tx"
|
||||||
#define D_SENSOR_PZEM_RX "PZEM Rx"
|
#define D_SENSOR_PZEM004_RX "PZEM004 Rx"
|
||||||
#define D_SENSOR_PZEM_TX "PZEM Tx"
|
#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_RX "SAir Rx"
|
||||||
#define D_SENSOR_SAIR_TX "SAir Tx"
|
#define D_SENSOR_SAIR_TX "SAir Tx"
|
||||||
#define D_SENSOR_SPI_CS "SPI CS"
|
#define D_SENSOR_SPI_CS "SPI CS"
|
||||||
|
@ -505,6 +524,9 @@
|
||||||
#define D_SENSOR_TM1638_STB "TM16 STB"
|
#define D_SENSOR_TM1638_STB "TM16 STB"
|
||||||
#define D_SENSOR_HX711_SCK "HX711 SCK"
|
#define D_SENSOR_HX711_SCK "HX711 SCK"
|
||||||
#define D_SENSOR_HX711_DAT "HX711 DAT"
|
#define D_SENSOR_HX711_DAT "HX711 DAT"
|
||||||
|
#define D_SENSOR_TX20_TX "TX20"
|
||||||
|
#define D_SENSOR_RFSEND "RFSend"
|
||||||
|
#define D_SENSOR_RFRECV "RFrecv"
|
||||||
|
|
||||||
// Units
|
// Units
|
||||||
#define D_UNIT_AMPERE "A"
|
#define D_UNIT_AMPERE "A"
|
||||||
|
@ -513,6 +535,7 @@
|
||||||
#define D_UNIT_HOUR "h"
|
#define D_UNIT_HOUR "h"
|
||||||
#define D_UNIT_INCREMENTS "inc"
|
#define D_UNIT_INCREMENTS "inc"
|
||||||
#define D_UNIT_KILOGRAM "kg"
|
#define D_UNIT_KILOGRAM "kg"
|
||||||
|
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
|
||||||
#define D_UNIT_KILOOHM "kOhm"
|
#define D_UNIT_KILOOHM "kOhm"
|
||||||
#define D_UNIT_KILOWATTHOUR "kWh"
|
#define D_UNIT_KILOWATTHOUR "kWh"
|
||||||
#define D_UNIT_LUX "lx"
|
#define D_UNIT_LUX "lx"
|
||||||
|
|
|
@ -461,6 +461,23 @@
|
||||||
#define D_HX_CAL_REFERENCE "Load reference weigth"
|
#define D_HX_CAL_REFERENCE "Load reference weigth"
|
||||||
#define D_HX_CAL_DONE "Calibrated"
|
#define D_HX_CAL_DONE "Calibrated"
|
||||||
#define D_HX_CAL_FAIL "Calibration failed"
|
#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
|
// sonoff_template.h
|
||||||
#define D_SENSOR_NONE "Κανένας"
|
#define D_SENSOR_NONE "Κανένας"
|
||||||
|
@ -482,8 +499,10 @@
|
||||||
#define D_SENSOR_IRRECV "IRrecv"
|
#define D_SENSOR_IRRECV "IRrecv"
|
||||||
#define D_SENSOR_MHZ_RX "MHZ Rx"
|
#define D_SENSOR_MHZ_RX "MHZ Rx"
|
||||||
#define D_SENSOR_MHZ_TX "MHZ Tx"
|
#define D_SENSOR_MHZ_TX "MHZ Tx"
|
||||||
#define D_SENSOR_PZEM_RX "PZEM Rx"
|
#define D_SENSOR_PZEM004_RX "PZEM004 Rx"
|
||||||
#define D_SENSOR_PZEM_TX "PZEM Tx"
|
#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_RX "SAir Rx"
|
||||||
#define D_SENSOR_SAIR_TX "SAir Tx"
|
#define D_SENSOR_SAIR_TX "SAir Tx"
|
||||||
#define D_SENSOR_SPI_CS "SPI CS"
|
#define D_SENSOR_SPI_CS "SPI CS"
|
||||||
|
@ -505,6 +524,9 @@
|
||||||
#define D_SENSOR_TM1638_STB "TM16 STB"
|
#define D_SENSOR_TM1638_STB "TM16 STB"
|
||||||
#define D_SENSOR_HX711_SCK "HX711 SCK"
|
#define D_SENSOR_HX711_SCK "HX711 SCK"
|
||||||
#define D_SENSOR_HX711_DAT "HX711 DAT"
|
#define D_SENSOR_HX711_DAT "HX711 DAT"
|
||||||
|
#define D_SENSOR_TX20_TX "TX20"
|
||||||
|
#define D_SENSOR_RFSEND "RFSend"
|
||||||
|
#define D_SENSOR_RFRECV "RFrecv"
|
||||||
|
|
||||||
// Units
|
// Units
|
||||||
#define D_UNIT_AMPERE "A"
|
#define D_UNIT_AMPERE "A"
|
||||||
|
@ -513,6 +535,7 @@
|
||||||
#define D_UNIT_HOUR "Hr"
|
#define D_UNIT_HOUR "Hr"
|
||||||
#define D_UNIT_INCREMENTS "inc"
|
#define D_UNIT_INCREMENTS "inc"
|
||||||
#define D_UNIT_KILOGRAM "kg"
|
#define D_UNIT_KILOGRAM "kg"
|
||||||
|
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
|
||||||
#define D_UNIT_KILOOHM "kOhm"
|
#define D_UNIT_KILOOHM "kOhm"
|
||||||
#define D_UNIT_KILOWATTHOUR "kWh"
|
#define D_UNIT_KILOWATTHOUR "kWh"
|
||||||
#define D_UNIT_LUX "lx"
|
#define D_UNIT_LUX "lx"
|
||||||
|
|
|
@ -461,6 +461,23 @@
|
||||||
#define D_HX_CAL_REFERENCE "Load reference weigth"
|
#define D_HX_CAL_REFERENCE "Load reference weigth"
|
||||||
#define D_HX_CAL_DONE "Calibrated"
|
#define D_HX_CAL_DONE "Calibrated"
|
||||||
#define D_HX_CAL_FAIL "Calibration failed"
|
#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
|
// sonoff_template.h
|
||||||
#define D_SENSOR_NONE "None"
|
#define D_SENSOR_NONE "None"
|
||||||
|
@ -482,8 +499,10 @@
|
||||||
#define D_SENSOR_IRRECV "IRrecv"
|
#define D_SENSOR_IRRECV "IRrecv"
|
||||||
#define D_SENSOR_MHZ_RX "MHZ Rx"
|
#define D_SENSOR_MHZ_RX "MHZ Rx"
|
||||||
#define D_SENSOR_MHZ_TX "MHZ Tx"
|
#define D_SENSOR_MHZ_TX "MHZ Tx"
|
||||||
#define D_SENSOR_PZEM_RX "PZEM Rx"
|
#define D_SENSOR_PZEM004_RX "PZEM004 Rx"
|
||||||
#define D_SENSOR_PZEM_TX "PZEM Tx"
|
#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_RX "SAir Rx"
|
||||||
#define D_SENSOR_SAIR_TX "SAir Tx"
|
#define D_SENSOR_SAIR_TX "SAir Tx"
|
||||||
#define D_SENSOR_SPI_CS "SPI CS"
|
#define D_SENSOR_SPI_CS "SPI CS"
|
||||||
|
@ -505,6 +524,9 @@
|
||||||
#define D_SENSOR_TM1638_STB "TM16 STB"
|
#define D_SENSOR_TM1638_STB "TM16 STB"
|
||||||
#define D_SENSOR_HX711_SCK "HX711 SCK"
|
#define D_SENSOR_HX711_SCK "HX711 SCK"
|
||||||
#define D_SENSOR_HX711_DAT "HX711 DAT"
|
#define D_SENSOR_HX711_DAT "HX711 DAT"
|
||||||
|
#define D_SENSOR_TX20_TX "TX20"
|
||||||
|
#define D_SENSOR_RFSEND "RFSend"
|
||||||
|
#define D_SENSOR_RFRECV "RFrecv"
|
||||||
|
|
||||||
// Units
|
// Units
|
||||||
#define D_UNIT_AMPERE "A"
|
#define D_UNIT_AMPERE "A"
|
||||||
|
@ -513,6 +535,7 @@
|
||||||
#define D_UNIT_HOUR "Hr"
|
#define D_UNIT_HOUR "Hr"
|
||||||
#define D_UNIT_INCREMENTS "inc"
|
#define D_UNIT_INCREMENTS "inc"
|
||||||
#define D_UNIT_KILOGRAM "kg"
|
#define D_UNIT_KILOGRAM "kg"
|
||||||
|
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
|
||||||
#define D_UNIT_KILOOHM "kOhm"
|
#define D_UNIT_KILOOHM "kOhm"
|
||||||
#define D_UNIT_KILOWATTHOUR "kWh"
|
#define D_UNIT_KILOWATTHOUR "kWh"
|
||||||
#define D_UNIT_LUX "lx"
|
#define D_UNIT_LUX "lx"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue