mirror of https://github.com/arendst/Tasmota.git
Merge branch 'development' into neopool-dev
This commit is contained in:
commit
19f4780e24
|
@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
|
|||
## [9.2.0.4]
|
||||
### Added
|
||||
- Function ``AddLog`` to provide logging for up to 128 (LOGSZ) characters to save stack space
|
||||
- Commands ``ChannelRemap``, ``MultiPWM``, ``AlexaCTRange``, ``PowerOnFade``, ``PWMCT``, ``WhiteBlend``, ``VirtualCT`` as synonyms for ``SetOption37, 68, 82, 91, 92, 105 and 106`` respectively
|
||||
|
||||
### Changed
|
||||
- Maximum chars in ``AddLog_P`` logging restored from 128 to 700 (MAX_LOGSZ) to solve broken error messages
|
||||
|
|
|
@ -65,6 +65,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
|
|||
- Command ``SetOption43 1..255`` to control Rotary step (#10407)
|
||||
- Command ``SetOption118 1`` to move ZbReceived from JSON message and into the subtopic replacing "SENSOR" default [#10353](https://github.com/arendst/Tasmota/issues/10353)
|
||||
- Command ``SetOption119 1`` to remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic [#10355](https://github.com/arendst/Tasmota/issues/10355)
|
||||
- Commands ``ChannelRemap``, ``MultiPWM``, ``AlexaCTRange``, ``PowerOnFade``, ``PWMCT``, ``WhiteBlend``, ``VirtualCT`` as synonyms for ``SetOption37, 68, 82, 91, 92, 105 and 106`` respectively
|
||||
- Milliseconds to console output [#10152](https://github.com/arendst/Tasmota/issues/10152)
|
||||
- Gpio ``Option_a1`` enabling PWM2 high impedance if powered off as used by Wyze bulbs [#10196](https://github.com/arendst/Tasmota/issues/10196)
|
||||
- Rotary No Pullup GPIO selection ``Rotary A/B_n`` [#10407](https://github.com/arendst/Tasmota/issues/10407)
|
||||
|
|
|
@ -93,15 +93,18 @@ uint8_t TasmotaModbus::ReceiveBuffer(uint8_t *buffer, uint8_t register_count)
|
|||
buffer[mb_len++] = data;
|
||||
if (3 == mb_len) {
|
||||
if (buffer[1] & 0x80) { // 01 84 02 f2 f1
|
||||
if (0 == buffer[2]) {
|
||||
return 3; // 3 = Illegal Data Value,
|
||||
}
|
||||
return buffer[2]; // 1 = Illegal Function,
|
||||
// 2 = Illegal Data Address,
|
||||
// 3 = Illegal Data Value,
|
||||
// 4 = Slave Error
|
||||
// 5 = Acknowledge but not finished (no error)
|
||||
// 6 = Slave Busy
|
||||
// 8 = Memory Parity error
|
||||
// 10 = Gateway Path Unavailable
|
||||
// 11 = Gateway Target device failed to respond
|
||||
// 2 = Illegal Data Address,
|
||||
// 3 = Illegal Data Value,
|
||||
// 4 = Slave Error
|
||||
// 5 = Acknowledge but not finished (no error)
|
||||
// 6 = Slave Busy
|
||||
// 8 = Memory Parity error
|
||||
// 10 = Gateway Path Unavailable
|
||||
// 11 = Gateway Target device failed to respond
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
## [1.1.0] - 2021-01-20
|
||||
|
||||
### Added
|
||||
- `NimBLEDevice::setOwnAddrType` added to enable the use of random and random-resolvable addresses, by asukiaaa
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
[Latest release ![Release Version](https://img.shields.io/github/release/h2zero/NimBLE-Arduino.svg?style=plastic)
|
||||
![Release Date](https://img.shields.io/github/release-date/h2zero/NimBLE-Arduino.svg?style=plastic)](https://github.com/h2zero/NimBLE-Arduino/releases/latest/)
|
||||
|
||||
Need help? Have questions or suggestions? Join the [![Gitter](https://badges.gitter.im/NimBLE-Arduino/community.svg)](https://gitter.im/NimBLE-Arduino/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
<br/>
|
||||
|
||||
# NimBLE-Arduino
|
||||
|
@ -57,6 +59,8 @@ Also see [Improvements_and_updates](docs/Improvements_and_updates.md) for inform
|
|||
|
||||
[Full API documentation and class list can be found here.](https://h2zero.github.io/esp-nimble-cpp/)
|
||||
|
||||
For added performance and optimizations see [Usage tips](docs/Usage_tips.md).
|
||||
|
||||
Check the Refactored_original_examples in the examples folder for highlights of the differences with the original library.
|
||||
|
||||
More advanced examples highlighting many available features are in examples/ NimBLE_Server, NimBLE_Client.
|
||||
|
|
|
@ -79,27 +79,24 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
|
|||
return;
|
||||
}
|
||||
|
||||
uint8_t *payLoad = advertisedDevice->getPayload();
|
||||
BLEUUID eddyUUID = (uint16_t)0xfeaa;
|
||||
|
||||
BLEUUID checkUrlUUID = (uint16_t)0xfeaa;
|
||||
|
||||
if (advertisedDevice->getServiceUUID().equals(checkUrlUUID))
|
||||
if (advertisedDevice->getServiceUUID().equals(eddyUUID))
|
||||
{
|
||||
if (payLoad[11] == 0x10)
|
||||
std::string serviceData = advertisedDevice->getServiceData(eddyUUID);
|
||||
if (serviceData[0] == 0x10)
|
||||
{
|
||||
Serial.println("Found an EddystoneURL beacon!");
|
||||
BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
|
||||
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
|
||||
|
||||
foundEddyURL.setData(eddyContent);
|
||||
foundEddyURL.setData(serviceData);
|
||||
std::string bareURL = foundEddyURL.getURL();
|
||||
if (bareURL[0] == 0x00)
|
||||
{
|
||||
size_t payLoadLen = advertisedDevice->getPayloadLength();
|
||||
Serial.println("DATA-->");
|
||||
for (int idx = 0; idx < payLoadLen; idx++)
|
||||
for (int idx = 0; idx < serviceData.length(); idx++)
|
||||
{
|
||||
Serial.printf("0x%08X ", payLoad[idx]);
|
||||
Serial.printf("0x%08X ", serviceData[idx]);
|
||||
}
|
||||
Serial.println("\nInvalid Data");
|
||||
return;
|
||||
|
@ -110,23 +107,15 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
|
|||
Serial.printf("TX power %d\n", foundEddyURL.getPower());
|
||||
Serial.println("\n");
|
||||
}
|
||||
else if (payLoad[11] == 0x20)
|
||||
else if (serviceData[0] == 0x20)
|
||||
{
|
||||
Serial.println("Found an EddystoneTLM beacon!");
|
||||
BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();
|
||||
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
|
||||
foundEddyURL.setData(serviceData);
|
||||
|
||||
eddyContent = "01234567890123";
|
||||
|
||||
for (int idx = 0; idx < 14; idx++)
|
||||
{
|
||||
eddyContent[idx] = payLoad[idx + 11];
|
||||
}
|
||||
|
||||
foundEddyURL.setData(eddyContent);
|
||||
Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt());
|
||||
Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp());
|
||||
int temp = (int)payLoad[16] + (int)(payLoad[15] << 8);
|
||||
int temp = (int)serviceData[5] + (int)(serviceData[4] << 8);
|
||||
float calcTemp = temp / 256.0f;
|
||||
Serial.printf("Reported temperature from data: %.2fC\n", calcTemp);
|
||||
Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount());
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
/** NimBLE_Server Demo:
|
||||
*
|
||||
* Demonstrates many of the available features of the NimBLE client library.
|
||||
*
|
||||
*
|
||||
* Created: on March 24 2020
|
||||
* Author: H2zero
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
@ -19,15 +19,15 @@ static uint32_t scanTime = 0; /** 0 = scan forever */
|
|||
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
** Remove as you see fit for your needs */
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) {
|
||||
Serial.println("Connected");
|
||||
/** After connection we should change the parameters if we don't need fast response times.
|
||||
* These settings are 150ms interval, 0 latency, 450ms timout.
|
||||
* These settings are 150ms interval, 0 latency, 450ms timout.
|
||||
* Timeout should be a multiple of the interval, minimum is 100ms.
|
||||
* I find a multiple of 3-5 * the interval works best for quick response/reconnect.
|
||||
* Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 60 * 10ms = 600ms timeout
|
||||
* Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 60 * 10ms = 600ms timeout
|
||||
*/
|
||||
pClient->updateConnParams(120,120,0,60);
|
||||
};
|
||||
|
@ -37,9 +37,9 @@ class ClientCallbacks : public NimBLEClientCallbacks {
|
|||
Serial.println(" Disconnected - Starting scan");
|
||||
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
||||
};
|
||||
|
||||
|
||||
/** Called when the peripheral requests a change to the connection parameters.
|
||||
* Return true to accept and apply them or false to reject and keep
|
||||
* Return true to accept and apply them or false to reject and keep
|
||||
* the currently used parameters. Default will return true.
|
||||
*/
|
||||
bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) {
|
||||
|
@ -55,7 +55,7 @@ class ClientCallbacks : public NimBLEClientCallbacks {
|
|||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/********************* Security handled here **********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
uint32_t onPassKeyRequest(){
|
||||
|
@ -85,7 +85,7 @@ class ClientCallbacks : public NimBLEClientCallbacks {
|
|||
|
||||
/** Define a class to handle the callbacks when advertisments are received */
|
||||
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
||||
|
||||
|
||||
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
|
||||
Serial.print("Advertised Device found: ");
|
||||
Serial.println(advertisedDevice->toString().c_str());
|
||||
|
@ -94,9 +94,9 @@ class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
|||
Serial.println("Found Our Service");
|
||||
/** stop scan before connecting */
|
||||
NimBLEDevice::getScan()->stop();
|
||||
/** Save the device reference in a global for the client to use*/
|
||||
/** Save the device reference in a global for the client to use*/
|
||||
advDevice = advertisedDevice;
|
||||
/** Ready to connect now */
|
||||
/** Ready to connect now */
|
||||
doConnect = true;
|
||||
}
|
||||
};
|
||||
|
@ -105,7 +105,7 @@ class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
|||
|
||||
/** Notification / Indication receiving handler callback */
|
||||
void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify){
|
||||
std::string str = (isNotify == true) ? "Notification" : "Indication";
|
||||
std::string str = (isNotify == true) ? "Notification" : "Indication";
|
||||
str += " from ";
|
||||
/** NimBLEAddress and NimBLEUUID have std::string operators */
|
||||
str += std::string(pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress());
|
||||
|
@ -128,10 +128,10 @@ static ClientCallbacks clientCB;
|
|||
/** Handles the provisioning of clients and connects / interfaces with the server */
|
||||
bool connectToServer() {
|
||||
NimBLEClient* pClient = nullptr;
|
||||
|
||||
|
||||
/** Check if we have a client we should reuse first **/
|
||||
if(NimBLEDevice::getClientListSize()) {
|
||||
/** Special case when we already know this device, we send false as the
|
||||
/** Special case when we already know this device, we send false as the
|
||||
* second argument in connect() to prevent refreshing the service database.
|
||||
* This saves considerable time and power.
|
||||
*/
|
||||
|
@ -142,7 +142,7 @@ bool connectToServer() {
|
|||
return false;
|
||||
}
|
||||
Serial.println("Reconnected client");
|
||||
}
|
||||
}
|
||||
/** We don't already have a client that knows this device,
|
||||
* we will check for a client that is disconnected that we can use.
|
||||
*/
|
||||
|
@ -150,28 +150,28 @@ bool connectToServer() {
|
|||
pClient = NimBLEDevice::getDisconnectedClient();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** No client to reuse? Create a new one. */
|
||||
if(!pClient) {
|
||||
if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) {
|
||||
Serial.println("Max clients reached - no more connections available");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
pClient = NimBLEDevice::createClient();
|
||||
|
||||
|
||||
Serial.println("New client created");
|
||||
|
||||
|
||||
pClient->setClientCallbacks(&clientCB, false);
|
||||
/** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout.
|
||||
* These settings are safe for 3 clients to connect reliably, can go faster if you have less
|
||||
/** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout.
|
||||
* These settings are safe for 3 clients to connect reliably, can go faster if you have less
|
||||
* connections. Timeout should be a multiple of the interval, minimum is 100ms.
|
||||
* Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 51 * 10ms = 510ms timeout
|
||||
* Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 51 * 10ms = 510ms timeout
|
||||
*/
|
||||
pClient->setConnectionParams(12,12,0,51);
|
||||
/** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */
|
||||
pClient->setConnectTimeout(5);
|
||||
|
||||
|
||||
|
||||
if (!pClient->connect(advDevice)) {
|
||||
/** Created a client but failed to connect, don't need to keep it as it has no data */
|
||||
|
@ -179,149 +179,147 @@ bool connectToServer() {
|
|||
Serial.println("Failed to connect, deleted client");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!pClient->isConnected()) {
|
||||
if (!pClient->connect(advDevice)) {
|
||||
Serial.println("Failed to connect");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Serial.print("Connected to: ");
|
||||
Serial.println(pClient->getPeerAddress().toString().c_str());
|
||||
Serial.print("RSSI: ");
|
||||
Serial.println(pClient->getRssi());
|
||||
|
||||
|
||||
/** Now we can read/write/subscribe the charateristics of the services we are interested in */
|
||||
NimBLERemoteService* pSvc = nullptr;
|
||||
NimBLERemoteCharacteristic* pChr = nullptr;
|
||||
NimBLERemoteDescriptor* pDsc = nullptr;
|
||||
|
||||
|
||||
pSvc = pClient->getService("DEAD");
|
||||
if(pSvc) { /** make sure it's not null */
|
||||
pChr = pSvc->getCharacteristic("BEEF");
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("Tasty")) {
|
||||
Serial.print("Wrote new value to: ");
|
||||
Serial.println(pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
Serial.print("The value of: ");
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" is now: ");
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||
* Unsubscribe parameter defaults are: response=false.
|
||||
*/
|
||||
if(pChr->canNotify()) {
|
||||
//if(!pChr->registerForNotify(notifyCB)) {
|
||||
if(!pChr->subscribe(true, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("Tasty")) {
|
||||
Serial.print("Wrote new value to: ");
|
||||
Serial.println(pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr->canRead()) {
|
||||
Serial.print("The value of: ");
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" is now: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||
* Unsubscribe parameter defaults are: response=false.
|
||||
*/
|
||||
if(pChr->canNotify()) {
|
||||
//if(!pChr->registerForNotify(notifyCB)) {
|
||||
if(!pChr->subscribe(true, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||
if(!pChr->subscribe(false, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||
if(!pChr->subscribe(false, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
|
||||
} else {
|
||||
Serial.println("DEAD service not found.");
|
||||
}
|
||||
|
||||
|
||||
pSvc = pClient->getService("BAAD");
|
||||
if(pSvc) { /** make sure it's not null */
|
||||
pChr = pSvc->getCharacteristic("F00D");
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
|
||||
if(pDsc) { /** make sure it's not null */
|
||||
Serial.print("Descriptor: ");
|
||||
Serial.print(pDsc->getUUID().toString().c_str());
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pDsc->readValue().c_str());
|
||||
}
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("No tip!")) {
|
||||
Serial.print("Wrote new value to: ");
|
||||
Serial.println(pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
Serial.print("The value of: ");
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" is now: ");
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||
* Unsubscribe parameter defaults are: response=false.
|
||||
*/
|
||||
if(pChr->canNotify()) {
|
||||
//if(!pChr->registerForNotify(notifyCB)) {
|
||||
if(!pChr->subscribe(true, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||
if(!pChr->subscribe(false, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
|
||||
if(pDsc) { /** make sure it's not null */
|
||||
Serial.print("Descriptor: ");
|
||||
Serial.print(pDsc->getUUID().toString().c_str());
|
||||
Serial.print(" Value: ");
|
||||
Serial.println(pDsc->readValue().c_str());
|
||||
}
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("No tip!")) {
|
||||
Serial.print("Wrote new value to: ");
|
||||
Serial.println(pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr->canRead()) {
|
||||
Serial.print("The value of: ");
|
||||
Serial.print(pChr->getUUID().toString().c_str());
|
||||
Serial.print(" is now: ");
|
||||
Serial.println(pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||
* Unsubscribe parameter defaults are: response=false.
|
||||
*/
|
||||
if(pChr->canNotify()) {
|
||||
//if(!pChr->registerForNotify(notifyCB)) {
|
||||
if(!pChr->subscribe(true, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||
if(!pChr->subscribe(false, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Serial.println("BAAD service not found.");
|
||||
}
|
||||
|
||||
|
||||
Serial.println("Done with this device!");
|
||||
return true;
|
||||
}
|
||||
|
@ -331,7 +329,7 @@ void setup (){
|
|||
Serial.println("Starting NimBLE Client");
|
||||
/** Initialize NimBLE, no device name spcified as we are not advertising */
|
||||
NimBLEDevice::init("");
|
||||
|
||||
|
||||
/** Set the IO capabilities of the device, each option will trigger a different pairing method.
|
||||
* BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing
|
||||
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
|
||||
|
@ -339,37 +337,37 @@ void setup (){
|
|||
*/
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
||||
|
||||
|
||||
/** 2 different ways to set security - both calls achieve the same result.
|
||||
* no bonding, no man in the middle protection, secure connections.
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
//NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
//NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||
|
||||
|
||||
/** Optional: set the transmit power, default is 3db */
|
||||
NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */
|
||||
|
||||
|
||||
/** Optional: set any devices you don't want to get advertisments from */
|
||||
// NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff"));
|
||||
|
||||
/** create new scan */
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
// NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff"));
|
||||
|
||||
/** create new scan */
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
/** create a callback that gets called when advertisers are found */
|
||||
pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
|
||||
|
||||
|
||||
/** Set scan interval (how often) and window (how long) in milliseconds */
|
||||
pScan->setInterval(45);
|
||||
pScan->setWindow(15);
|
||||
|
||||
|
||||
/** Active scan will gather scan response data from advertisers
|
||||
* but will use more energy from both devices
|
||||
*/
|
||||
pScan->setActiveScan(true);
|
||||
/** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever
|
||||
* Optional callback for when scanning stops.
|
||||
* Optional callback for when scanning stops.
|
||||
*/
|
||||
pScan->start(scanTime, scanEndedCB);
|
||||
}
|
||||
|
@ -380,15 +378,15 @@ void loop (){
|
|||
while(!doConnect){
|
||||
delay(1);
|
||||
}
|
||||
|
||||
|
||||
doConnect = false;
|
||||
|
||||
|
||||
/** Found a device we want to connect to, do it now */
|
||||
if(connectToServer()) {
|
||||
Serial.println("Success! we should now be getting notifications, scanning for more!");
|
||||
} else {
|
||||
Serial.println("Failed to connect, starting scan");
|
||||
}
|
||||
|
||||
|
||||
NimBLEDevice::getScan()->start(scanTime,scanEndedCB);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name=NimBLE-Arduino
|
||||
version=1.0.2
|
||||
version=1.1.0
|
||||
author=h2zero
|
||||
maintainer=h2zero <powellperalta@gmail.com>
|
||||
sentence=Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE.
|
||||
|
|
|
@ -100,9 +100,10 @@ NimBLEClient::~NimBLEClient() {
|
|||
* be called to reset the host in the case of a stalled controller.
|
||||
*/
|
||||
void NimBLEClient::dcTimerCb(ble_npl_event *event) {
|
||||
NimBLEClient *pClient = (NimBLEClient*)event->arg;
|
||||
/* NimBLEClient *pClient = (NimBLEClient*)event->arg;
|
||||
NIMBLE_LOGC(LOG_TAG, "Timed out disconnecting from %s - resetting host",
|
||||
std::string(pClient->getPeerAddress()).c_str());
|
||||
*/
|
||||
ble_hs_sched_reset(BLE_HS_ECONTROLLER);
|
||||
}
|
||||
|
||||
|
@ -182,25 +183,30 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if(isConnected() || m_pTaskData != nullptr) {
|
||||
if(isConnected() || m_connEstablished || m_pTaskData != nullptr) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Client busy, connected to %s, id=%d",
|
||||
std::string(m_peerAddress).c_str(), getConnId());
|
||||
return false;
|
||||
}
|
||||
|
||||
ble_addr_t peerAddr_t;
|
||||
memcpy(&peerAddr_t.val, address.getNative(),6);
|
||||
peerAddr_t.type = address.getType();
|
||||
if(ble_gap_conn_find_by_addr(&peerAddr_t, NULL) == 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "A connection to %s already exists",
|
||||
address.toString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(address == NimBLEAddress("")) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid peer address;(NULL)");
|
||||
return false;
|
||||
} else if(m_peerAddress != address) {
|
||||
} else {
|
||||
m_peerAddress = address;
|
||||
}
|
||||
|
||||
ble_addr_t peerAddr_t;
|
||||
memcpy(&peerAddr_t.val, m_peerAddress.getNative(),6);
|
||||
peerAddr_t.type = m_peerAddress.getType();
|
||||
|
||||
|
||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
||||
m_pTaskData = &taskData;
|
||||
int rc = 0;
|
||||
|
||||
/* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
|
||||
|
@ -213,13 +219,12 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||
NimBLEClient::handleGapEvent, this);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
m_pTaskData = &taskData;
|
||||
break;
|
||||
|
||||
case BLE_HS_EBUSY:
|
||||
// Scan was still running, stop it and try again
|
||||
if (!NimBLEDevice::getScan()->stop()) {
|
||||
return false;
|
||||
rc = BLE_HS_EUNKNOWN;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -227,7 +232,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||
// A connection to this device already exists, do not connect twice.
|
||||
NIMBLE_LOGE(LOG_TAG, "Already connected to device; addr=%s",
|
||||
std::string(m_peerAddress).c_str());
|
||||
return false;
|
||||
break;
|
||||
|
||||
case BLE_HS_EALREADY:
|
||||
// Already attemting to connect to this device, cancel the previous
|
||||
|
@ -235,17 +240,22 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||
NIMBLE_LOGE(LOG_TAG, "Already attempting to connect to %s - cancelling",
|
||||
std::string(m_peerAddress).c_str());
|
||||
ble_gap_conn_cancel();
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to connect to %s, rc=%d; %s",
|
||||
std::string(m_peerAddress).c_str(),
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (rc == BLE_HS_EBUSY);
|
||||
|
||||
if(rc != 0) {
|
||||
m_pTaskData = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the connect timeout time +1 second for the connection to complete
|
||||
if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
|
||||
m_pTaskData = nullptr;
|
||||
|
@ -255,7 +265,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||
disconnect();
|
||||
} else {
|
||||
// workaround; if the controller doesn't cancel the connection
|
||||
// at the timeout cancel it here.
|
||||
// at the timeout, cancel it here.
|
||||
NIMBLE_LOGE(LOG_TAG, "Connect timeout - cancelling");
|
||||
ble_gap_conn_cancel();
|
||||
}
|
||||
|
@ -269,7 +279,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
|||
// If the failure was not a result of a disconnection
|
||||
// make sure we disconnect now to avoid dangling connections
|
||||
if(isConnected()) {
|
||||
ble_gap_terminate(m_conn_id, BLE_ERR_REM_USER_CONN_TERM);
|
||||
disconnect();
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
|
@ -325,26 +335,35 @@ bool NimBLEClient::secureConnection() {
|
|||
*/
|
||||
int NimBLEClient::disconnect(uint8_t reason) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> disconnect()");
|
||||
|
||||
int rc = 0;
|
||||
if(isConnected()){
|
||||
rc = ble_gap_terminate(m_conn_id, reason);
|
||||
if (rc == 0) {
|
||||
ble_addr_t peerAddr_t;
|
||||
memcpy(&peerAddr_t.val, m_peerAddress.getNative(),6);
|
||||
peerAddr_t.type = m_peerAddress.getType();
|
||||
if(isConnected()) {
|
||||
// If the timer was already started, ignore this call.
|
||||
if(ble_npl_callout_is_active(&m_dcTimer)) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Already disconnecting, timer started");
|
||||
return BLE_HS_EALREADY;
|
||||
}
|
||||
|
||||
// Set the disconnect timeout to the supervison timeout time + 1 second
|
||||
// In case the event triggers shortly after the supervision timeout.
|
||||
// We don't want to prematurely reset the host.
|
||||
ble_gap_conn_desc desc;
|
||||
if(ble_gap_conn_find_by_addr(&peerAddr_t, &desc) == 0){
|
||||
ble_npl_time_t ticks;
|
||||
ble_npl_time_ms_to_ticks((desc.supervision_timeout + 100) * 10, &ticks);
|
||||
ble_npl_callout_reset(&m_dcTimer, ticks);
|
||||
NIMBLE_LOGD(LOG_TAG, "DC TIMEOUT = %dms", (desc.supervision_timeout + 100) * 10);
|
||||
ble_gap_conn_desc desc;
|
||||
if(ble_gap_conn_find(m_conn_id, &desc) != 0){
|
||||
NIMBLE_LOGI(LOG_TAG, "Connection ID not found");
|
||||
return BLE_HS_EALREADY;
|
||||
}
|
||||
|
||||
// We use a timer to detect a controller error in the event that it does
|
||||
// not inform the stack when disconnection is complete.
|
||||
// This is a common error in certain esp-idf versions.
|
||||
// The disconnect timeout time is the supervison timeout time + 1 second.
|
||||
// In the case that the event happenss shortly after the supervision timeout
|
||||
// we don't want to prematurely reset the host.
|
||||
ble_npl_time_t ticks;
|
||||
ble_npl_time_ms_to_ticks((desc.supervision_timeout + 100) * 10, &ticks);
|
||||
ble_npl_callout_reset(&m_dcTimer, ticks);
|
||||
|
||||
rc = ble_gap_terminate(m_conn_id, reason);
|
||||
if (rc != 0) {
|
||||
if(rc != BLE_HS_EALREADY) {
|
||||
ble_npl_callout_stop(&m_dcTimer);
|
||||
}
|
||||
} else if (rc != BLE_HS_EALREADY) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
}
|
||||
|
@ -359,12 +378,12 @@ int NimBLEClient::disconnect(uint8_t reason) {
|
|||
|
||||
/**
|
||||
* @brief Set the connection paramaters to use when connecting to a server.
|
||||
* @param [in] minInterval minimum connection interval in 0.625ms units.
|
||||
* @param [in] maxInterval maximum connection interval in 0.625ms units.
|
||||
* @param [in] latency number of packets allowed to skip (extends max interval)
|
||||
* @param [in] timeout the timeout time in 10ms units before disconnecting
|
||||
* @param [in] scanInterval the scan interval to use when attempting to connect in 0.625ms units.
|
||||
* @param [in] scanWindow the scan window to use when attempting to connect in 0.625ms units.
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||
* @param [in] scanInterval The scan interval to use when attempting to connect in 0.625ms units.
|
||||
* @param [in] scanWindow The scan window to use when attempting to connect in 0.625ms units.
|
||||
*/
|
||||
void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout,
|
||||
|
@ -391,10 +410,10 @@ void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterva
|
|||
/**
|
||||
* @brief Update the connection parameters:
|
||||
* * Can only be used after a connection has been established.
|
||||
* @param [in] minInterval minimum connection interval in 0.625ms units.
|
||||
* @param [in] maxInterval maximum connection interval in 0.625ms units.
|
||||
* @param [in] latency number of packets allowed to skip (extends max interval)
|
||||
* @param [in] timeout the timeout time in 10ms units before disconnecting
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||
*/
|
||||
void NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout)
|
||||
|
@ -797,14 +816,15 @@ uint16_t NimBLEClient::getMTU() {
|
|||
break;
|
||||
}
|
||||
|
||||
client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||
|
||||
// Stop the disconnect timer since we are now disconnected.
|
||||
ble_npl_callout_stop(&client->m_dcTimer);
|
||||
|
||||
// Remove the device from ignore list so we will scan it again
|
||||
NimBLEDevice::removeIgnored(client->m_peerAddress);
|
||||
|
||||
// No longer connected, clear the connection ID.
|
||||
client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||
|
||||
// If we received a connected event but did not get established (no PDU)
|
||||
// then a disconnect event will be sent but we should not send it to the
|
||||
// app for processing. Instead we will ensure the task is released
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
#include "NimBLEHIDDevice.h"
|
||||
#include "NimBLE2904.h"
|
||||
|
||||
/**
|
||||
* @brief Construct a default NimBLEHIDDevice object.
|
||||
* @param [in] server A pointer to the server instance this HID Device will use.
|
||||
*/
|
||||
NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
|
||||
/*
|
||||
* Here we create mandatory services described in bluetooth specification
|
||||
|
@ -61,15 +65,18 @@ NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
|
|||
NimBLEHIDDevice::~NimBLEHIDDevice() {
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
/**
|
||||
* @brief Set the report map data formatting information.
|
||||
* @param [in] map A pointer to an array with the values to set.
|
||||
* @param [in] size The number of values in the array.
|
||||
*/
|
||||
void NimBLEHIDDevice::reportMap(uint8_t* map, uint16_t size) {
|
||||
m_reportMapCharacteristic->setValue(map, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief This function suppose to be called at the end, when we have created all characteristics we need to build HID service
|
||||
/**
|
||||
* @brief Start the HID device services.\n
|
||||
* This function called when all the services have been created.
|
||||
*/
|
||||
void NimBLEHIDDevice::startServices() {
|
||||
m_deviceInfoService->start();
|
||||
|
@ -77,41 +84,47 @@ void NimBLEHIDDevice::startServices() {
|
|||
m_batteryService->start();
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create manufacturer characteristic (this characteristic is optional)
|
||||
/**
|
||||
* @brief Create a manufacturer characteristic (this characteristic is optional).
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::manufacturer() {
|
||||
m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, NIMBLE_PROPERTY::READ);
|
||||
return m_manufacturerCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief Set manufacturer name
|
||||
* @param [in] name manufacturer name
|
||||
* @param [in] name The manufacturer name of this HID device.
|
||||
*/
|
||||
void NimBLEHIDDevice::manufacturer(std::string name) {
|
||||
m_manufacturerCharacteristic->setValue(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
/**
|
||||
* @brief Sets the Plug n Play characterisc value.
|
||||
* @param [in] sig The vendor ID source number.
|
||||
* @param [in[ vid The vendor ID number.
|
||||
* @param [in] pid The product ID number.
|
||||
* @param [in] version The produce version number.
|
||||
*/
|
||||
void NimBLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) {
|
||||
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version };
|
||||
m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
/**
|
||||
* @brief Sets the HID Information characteristic value.
|
||||
* @param [in] country The country code for the device.
|
||||
* @param [in] flags The HID Class Specification release number to use.
|
||||
*/
|
||||
void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
|
||||
uint8_t info[] = { 0x11, 0x1, country, flags };
|
||||
m_hidInfoCharacteristic->setValue(info, sizeof(info));
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create input report characteristic that need to be saved as new characteristic object so can be further used
|
||||
* @param [in] reportID input report ID, the same as in report map for input object related to created characteristic
|
||||
/**
|
||||
* @brief Create input report characteristic
|
||||
* @param [in] reportID input report ID, the same as in report map for input object related to the characteristic
|
||||
* @return pointer to new input report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
|
||||
|
@ -124,9 +137,9 @@ NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
|
|||
return inputReportCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create output report characteristic that need to be saved as new characteristic object so can be further used
|
||||
* @param [in] reportID Output report ID, the same as in report map for output object related to created characteristic
|
||||
/**
|
||||
* @brief Create output report characteristic
|
||||
* @param [in] reportID Output report ID, the same as in report map for output object related to the characteristic
|
||||
* @return Pointer to new output report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
|
||||
|
@ -139,9 +152,9 @@ NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
|
|||
return outputReportCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create feature report characteristic that need to be saved as new characteristic object so can be further used
|
||||
* @param [in] reportID Feature report ID, the same as in report map for feature object related to created characteristic
|
||||
/**
|
||||
* @brief Create feature report characteristic.
|
||||
* @param [in] reportID Feature report ID, the same as in report map for feature object related to the characteristic
|
||||
* @return Pointer to new feature report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) {
|
||||
|
@ -154,34 +167,38 @@ NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) {
|
|||
return featureReportCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
/**
|
||||
* @brief Creates a keyboard boot input report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::bootInput() {
|
||||
return m_hidService->createCharacteristic((uint16_t) 0x2a22, NIMBLE_PROPERTY::NOTIFY);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
/**
|
||||
* @brief Create a keyboard boot output report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::bootOutput() {
|
||||
return m_hidService->createCharacteristic((uint16_t) 0x2a32, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
/**
|
||||
* @brief Returns a pointer to the HID control point characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::hidControl() {
|
||||
return m_hidControlCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
/**
|
||||
* @brief Returns a pointer to the protocol mode characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::protocolMode() {
|
||||
return m_protocolModeCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the battery level characteristic value.
|
||||
* @param [in] level The battery level value.
|
||||
*/
|
||||
void NimBLEHIDDevice::setBatteryLevel(uint8_t level) {
|
||||
m_batteryLevelCharacteristic->setValue(&level, 1);
|
||||
}
|
||||
|
@ -208,22 +225,23 @@ BLECharacteristic* BLEHIDDevice::hidInfo() {
|
|||
return m_hidInfoCharacteristic;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
* @brief
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the device information service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::deviceInfo() {
|
||||
return m_deviceInfoService;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
/**
|
||||
* @brief Returns a pointer to the HID service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::hidService() {
|
||||
return m_hidService;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
/**
|
||||
* @brief @brief Returns a pointer to the battery service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::batteryService() {
|
||||
return m_batteryService;
|
||||
|
|
|
@ -36,6 +36,10 @@
|
|||
#define HID_DIGITAL_PEN 0x03C7
|
||||
#define HID_BARCODE 0x03C8
|
||||
|
||||
|
||||
/**
|
||||
* @brief A model of a %BLE Human Interface Device.
|
||||
*/
|
||||
class NimBLEHIDDevice {
|
||||
public:
|
||||
NimBLEHIDDevice(NimBLEServer*);
|
||||
|
|
|
@ -621,7 +621,13 @@ uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
|
|||
|
||||
|
||||
/**
|
||||
* Update connection parameters can be called only after connection has been established
|
||||
* @brief Request an Update the connection parameters:
|
||||
* * Can only be used after a connection has been established.
|
||||
* @param [in] conn_handle The connection handle of the peer to send the request to.
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||
*/
|
||||
void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
||||
uint16_t minInterval, uint16_t maxInterval,
|
||||
|
|
|
@ -420,6 +420,13 @@
|
|||
#define D_JSON_MAXENERGYREACHED "MaxEnergyReached"
|
||||
|
||||
// Commands xdrv_04_light.ino
|
||||
#define D_SO_CHANNELREMAP "ChannelRemap" // SO37
|
||||
#define D_SO_MULTIPWM "MultiPWM" // SO68
|
||||
#define D_SO_ALEXACTRANGE "AlexaCTRange" // SO82
|
||||
#define D_SO_POWERONFADE "PowerOnFade" // SO91
|
||||
#define D_SO_PWMCT "PWMCT" // SO92
|
||||
#define D_SO_WHITEBLEND "WhiteBlend" // SO105
|
||||
#define D_SO_VIRTUALCT "VirtualCT" // SO106
|
||||
#define D_CMND_CHANNEL "Channel"
|
||||
#define D_CMND_COLOR "Color"
|
||||
#define D_CMND_COLORTEMPERATURE "CT"
|
||||
|
@ -522,6 +529,12 @@
|
|||
|
||||
// Commands xdrv_23_zigbee.ino
|
||||
#define D_PRFX_ZB "Zb"
|
||||
#define D_SO_ZIGBEE_NAMEKEY "NameKey"
|
||||
#define D_SO_ZIGBEE_DEVICETOPIC "DeviceTopic"
|
||||
#define D_SO_ZIGBEE_NOPREFIX "NoPrefix"
|
||||
#define D_SO_ZIGBEE_ENDPOINTSUFFIX "EndpointSuffix"
|
||||
#define D_SO_ZIGBEE_NOAUTOBIND "NoAutoBind"
|
||||
#define D_SO_ZIGBEE_NAMETOPIC "NameTopic"
|
||||
#define D_ZIGBEE_NOT_STARTED "Zigbee not started"
|
||||
#define D_CMND_ZIGBEE_PERMITJOIN "PermitJoin"
|
||||
#define D_CMND_ZIGBEE_STATUS "Status"
|
||||
|
@ -739,6 +752,7 @@ const char S_JSON_DRIVER_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_DRIVE
|
|||
|
||||
const char S_JSON_SVALUE_ACTION_SVALUE[] PROGMEM = "{\"%s\":{\"Action\":\"%s\"}}";
|
||||
|
||||
const char JSON_SNS_F_TEMP[] PROGMEM = ",\"%s\":{\"" D_JSON_TEMPERATURE "\":%*_f}";
|
||||
const char JSON_SNS_TEMP[] PROGMEM = ",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}";
|
||||
|
||||
const char JSON_SNS_ILLUMINANCE[] PROGMEM = ",\"%s\":{\"" D_JSON_ILLUMINANCE "\":%d}";
|
||||
|
@ -771,7 +785,9 @@ const float kSpeedConversionFactor[] = {1, // none
|
|||
// xdrv_02_webserver.ino
|
||||
#ifdef USE_WEBSERVER
|
||||
// {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
||||
const char HTTP_SNS_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%s " D_UNIT_DEGREE "%c{e}";
|
||||
const char HTTP_SNS_F_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%*_f " D_UNIT_DEGREE "%c{e}";
|
||||
//const char HTTP_SNS_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%s " D_UNIT_DEGREE "%c{e}";
|
||||
|
||||
const char HTTP_SNS_HUM[] PROGMEM = "{s}%s " D_HUMIDITY "{m}%s " D_UNIT_PERCENT "{e}";
|
||||
const char HTTP_SNS_DEW[] PROGMEM = "{s}%s " D_DEWPOINT "{m}%s " D_UNIT_DEGREE "%c{e}";
|
||||
const char HTTP_SNS_PRESSURE[] PROGMEM = "{s}%s " D_PRESSURE "{m}%s " "%s{e}";
|
||||
|
|
|
@ -916,8 +916,8 @@ int GetCommandCode(char* destination, size_t destination_size, const char* needl
|
|||
return result;
|
||||
}
|
||||
|
||||
bool DecodeCommand(const char* haystack, void (* const MyCommand[])(void))
|
||||
{
|
||||
bool DecodeCommand(const char* haystack, void (* const MyCommand[])(void), const uint8_t *synonyms = nullptr);
|
||||
bool DecodeCommand(const char* haystack, void (* const MyCommand[])(void), const uint8_t *synonyms) {
|
||||
GetTextIndexed(XdrvMailbox.command, CMDSZ, 0, haystack); // Get prefix if available
|
||||
int prefix_length = strlen(XdrvMailbox.command);
|
||||
if (prefix_length) {
|
||||
|
@ -927,10 +927,18 @@ bool DecodeCommand(const char* haystack, void (* const MyCommand[])(void))
|
|||
return false; // Prefix not in command
|
||||
}
|
||||
}
|
||||
size_t syn_count = synonyms ? pgm_read_byte(synonyms) : 0;
|
||||
int command_code = GetCommandCode(XdrvMailbox.command + prefix_length, CMDSZ, XdrvMailbox.topic + prefix_length, haystack);
|
||||
if (command_code > 0) { // Skip prefix
|
||||
XdrvMailbox.command_code = command_code -1;
|
||||
MyCommand[XdrvMailbox.command_code]();
|
||||
if (command_code > syn_count) {
|
||||
// We passed the synonyms zone, it's a regular command
|
||||
XdrvMailbox.command_code = command_code - 1 - syn_count;
|
||||
MyCommand[XdrvMailbox.command_code]();
|
||||
} else {
|
||||
// We have a SetOption synonym
|
||||
XdrvMailbox.index = pgm_read_byte(synonyms + command_code);
|
||||
CmndSetoptionBase(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -83,9 +83,7 @@ void ResponseCmndNumber(int value)
|
|||
|
||||
void ResponseCmndFloat(float value, uint32_t decimals)
|
||||
{
|
||||
char stemp1[TOPSZ];
|
||||
dtostrfd(value, decimals, stemp1);
|
||||
Response_P(S_JSON_COMMAND_XVALUE, XdrvMailbox.command, stemp1); // Return float value without quotes
|
||||
Response_P(PSTR("{\"%s\":%*_f}"), XdrvMailbox.command, decimals, &value); // Return float value without quotes
|
||||
}
|
||||
|
||||
void ResponseCmndIdxNumber(int value)
|
||||
|
@ -507,12 +505,21 @@ void CmndStatus(void)
|
|||
}
|
||||
|
||||
if ((0 == payload) || (5 == payload)) {
|
||||
/*
|
||||
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"" D_JSON_GATEWAY "\":\"%s\",\""
|
||||
D_JSON_SUBNETMASK "\":\"%s\",\"" D_JSON_DNSSERVER "\":\"%s\",\"" D_JSON_MAC "\":\"%s\",\""
|
||||
D_CMND_WEBSERVER "\":%d,\"" D_CMND_WIFICONFIG "\":%d,\"" D_CMND_WIFIPOWER "\":%s}}"),
|
||||
NetworkHostname(), NetworkAddress().toString().c_str(), IPAddress(Settings.ipv4_address[1]).toString().c_str(),
|
||||
IPAddress(Settings.ipv4_address[2]).toString().c_str(), IPAddress(Settings.ipv4_address[3]).toString().c_str(), NetworkMacAddress().c_str(),
|
||||
Settings.webserver, Settings.sta_config, WifiGetOutputPower().c_str());
|
||||
*/
|
||||
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\""
|
||||
D_JSON_GATEWAY "\":\"%_I\",\"" D_JSON_SUBNETMASK "\":\"%_I\",\"" D_JSON_DNSSERVER "\":\"%_I\",\""
|
||||
D_JSON_MAC "\":\"%s\",\"" D_CMND_WEBSERVER "\":%d,\"" D_CMND_WIFICONFIG "\":%d,\"" D_CMND_WIFIPOWER "\":%s}}"),
|
||||
NetworkHostname(), NetworkAddress().toString().c_str(),
|
||||
Settings.ipv4_address[1], Settings.ipv4_address[2], Settings.ipv4_address[3],
|
||||
NetworkMacAddress().c_str(), Settings.webserver, Settings.sta_config, WifiGetOutputPower().c_str());
|
||||
|
||||
MqttPublishPrefixTopic_P(STAT, PSTR(D_CMND_STATUS "5"));
|
||||
}
|
||||
|
||||
|
@ -835,10 +842,17 @@ void CmndSavedata(void)
|
|||
ResponseCmndChar((Settings.save_data > 1) ? stemp1 : GetStateText(Settings.save_data));
|
||||
}
|
||||
|
||||
void CmndSetoption(void)
|
||||
{
|
||||
void CmndSetoption(void) {
|
||||
snprintf_P(XdrvMailbox.command, CMDSZ, PSTR(D_CMND_SETOPTION)); // Rename result shortcut command SO to SetOption
|
||||
CmndSetoptionBase(1);
|
||||
}
|
||||
|
||||
void CmndSetoptionBase(bool indexed) {
|
||||
// Allow a command to access a single SetOption by it's command name
|
||||
// indexed = 0 : No index will be returned attached to the command
|
||||
// {"ClockDirection":"OFF"}
|
||||
// indexed = 1 : The SetOption index will be returned with the command
|
||||
// {"SetOption16":"OFF"}
|
||||
if (XdrvMailbox.index < 146) {
|
||||
uint32_t ptype;
|
||||
uint32_t pindex;
|
||||
|
@ -981,7 +995,11 @@ void CmndSetoption(void)
|
|||
|
||||
if (ptype < 99) {
|
||||
if (1 == ptype) {
|
||||
ResponseCmndIdxNumber(Settings.param[pindex]);
|
||||
if (indexed) {
|
||||
ResponseCmndIdxNumber(Settings.param[pindex]);
|
||||
} else {
|
||||
ResponseCmndNumber(Settings.param[pindex]);
|
||||
}
|
||||
} else {
|
||||
uint32_t flag = Settings.flag.data;
|
||||
if (3 == ptype) {
|
||||
|
@ -993,7 +1011,11 @@ void CmndSetoption(void)
|
|||
else if (5 == ptype) {
|
||||
flag = Settings.flag5.data;
|
||||
}
|
||||
ResponseCmndIdxChar(GetStateText(bitRead(flag, pindex)));
|
||||
if (indexed) {
|
||||
ResponseCmndIdxChar(GetStateText(bitRead(flag, pindex)));
|
||||
} else {
|
||||
ResponseCmndChar(GetStateText(bitRead(flag, pindex)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -475,17 +475,15 @@ void StartWebserver(int type, IPAddress ipweb)
|
|||
#if LWIP_IPV6
|
||||
String ipv6_addr = WifiGetIPv6();
|
||||
if (ipv6_addr!="") {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s and IPv6 global address %s "),
|
||||
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", ipweb.toString().c_str(), ipv6_addr.c_str());
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I and IPv6 global address %s "),
|
||||
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", (uint32_t)ipweb, ipv6_addr.c_str());
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"),
|
||||
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", ipweb.toString().c_str());
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I"),
|
||||
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", (uint32_t)ipweb);
|
||||
}
|
||||
#else
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"),
|
||||
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", ipweb.toString().c_str());
|
||||
// AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I"),
|
||||
// NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", (uint32_t)ipweb);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I"),
|
||||
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", (uint32_t)ipweb);
|
||||
#endif // LWIP_IPV6 = 1
|
||||
TasmotaGlobal.rules_flag.http_init = 1;
|
||||
}
|
||||
|
@ -785,11 +783,15 @@ void WSContentSpaceButton(uint32_t title_index)
|
|||
WSContentButton(title_index);
|
||||
}
|
||||
|
||||
void WSContentSend_Temp(const char *types, float f_temperature) {
|
||||
WSContentSend_PD(HTTP_SNS_F_TEMP, types, Settings.flag2.temperature_resolution, &f_temperature, TempUnit());
|
||||
}
|
||||
|
||||
void WSContentSend_THD(const char *types, float f_temperature, float f_humidity)
|
||||
{
|
||||
WSContentSend_Temp(types, f_temperature);
|
||||
|
||||
char parameter[FLOATSZ];
|
||||
dtostrfd(f_temperature, Settings.flag2.temperature_resolution, parameter);
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, types, parameter, TempUnit());
|
||||
dtostrfd(f_humidity, Settings.flag2.humidity_resolution, parameter);
|
||||
WSContentSend_PD(HTTP_SNS_HUM, types, parameter);
|
||||
dtostrfd(CalcTempHumToDew(f_temperature, f_humidity), Settings.flag2.temperature_resolution, parameter);
|
||||
|
|
|
@ -129,6 +129,10 @@ enum LightSchemes { LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_M
|
|||
const uint8_t LIGHT_COLOR_SIZE = 25; // Char array scolor size
|
||||
|
||||
const char kLightCommands[] PROGMEM = "|" // No prefix
|
||||
// SetOptions synonyms
|
||||
D_SO_CHANNELREMAP "|" D_SO_MULTIPWM "|" D_SO_ALEXACTRANGE "|" D_SO_POWERONFADE "|" D_SO_PWMCT "|"
|
||||
D_SO_WHITEBLEND "|" D_SO_VIRTUALCT "|"
|
||||
// Other commands
|
||||
D_CMND_COLOR "|" D_CMND_COLORTEMPERATURE "|" D_CMND_DIMMER "|" D_CMND_DIMMER_RANGE "|" D_CMND_DIMMER_STEP "|" D_CMND_LEDTABLE "|" D_CMND_FADE "|"
|
||||
D_CMND_RGBWWTABLE "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|"
|
||||
D_CMND_WHITE "|" D_CMND_CHANNEL "|" D_CMND_HSBCOLOR
|
||||
|
@ -144,6 +148,12 @@ const char kLightCommands[] PROGMEM = "|" // No prefix
|
|||
#endif // USE_DGR_LIGHT_SEQUENCE
|
||||
"|UNDOCA" ;
|
||||
|
||||
const uint8_t kLightSynonyms[] PROGMEM = {
|
||||
7, // number of entries
|
||||
37, 68, 82, 91, 92,
|
||||
105, 106,
|
||||
};
|
||||
|
||||
void (* const LightCommand[])(void) PROGMEM = {
|
||||
&CmndColor, &CmndColorTemperature, &CmndDimmer, &CmndDimmerRange, &CmndDimmerStep, &CmndLedTable, &CmndFade,
|
||||
&CmndRgbwwTable, &CmndScheme, &CmndSpeed, &CmndWakeup, &CmndWakeupDuration,
|
||||
|
@ -3078,7 +3088,7 @@ bool Xdrv04(uint8_t function)
|
|||
LightSetPower();
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kLightCommands, LightCommand);
|
||||
result = DecodeCommand(kLightCommands, LightCommand, kLightSynonyms);
|
||||
if (!result) {
|
||||
result = XlgtCall(FUNC_COMMAND);
|
||||
}
|
||||
|
|
|
@ -1303,7 +1303,7 @@ void TuyaSensorsShow(bool json)
|
|||
if (TuyaGetDpId(sensor) != 0) {
|
||||
switch (sensor) {
|
||||
case 71:
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, "", dtostrfd(Tuya.Sensors[0], Settings.flag2.temperature_resolution, tempval), TempUnit());
|
||||
WSContentSend_Temp("", Tuya.Sensors[0]);
|
||||
break;
|
||||
case 72:
|
||||
WSContentSend_PD(PSTR("{s}" D_TEMPERATURE " Set{m}%s " D_UNIT_DEGREE "%c{e}"),
|
||||
|
|
|
@ -107,6 +107,7 @@ public:
|
|||
|
||||
#ifdef USE_ZIGBEE_EZSP
|
||||
uint32_t permit_end_time = 0; // timestamp when permit join ends
|
||||
uint16_t ezsp_version = 0;
|
||||
#elif defined(USE_ZIGBEE_ZNP)
|
||||
bool permit_end_time = false; // in ZNP mode it's only a boolean
|
||||
#endif
|
||||
|
|
|
@ -151,59 +151,94 @@ void ZigbeeHueGroups(String * lights) {
|
|||
}
|
||||
}
|
||||
|
||||
void ZigbeeSendHue(uint16_t shortaddr, uint16_t cluster, uint8_t cmd, const SBuffer & s) {
|
||||
zigbeeZCLSendCmd(ZigbeeZCLSendMessage({
|
||||
shortaddr,
|
||||
0 /* groupaddr */,
|
||||
cluster /*cluster*/,
|
||||
0 /* endpoint */,
|
||||
cmd /* cmd */,
|
||||
0, /* manuf */
|
||||
true /* cluster specific */,
|
||||
true /* response */,
|
||||
false /* discover route */,
|
||||
0, /* zcl transaction id */
|
||||
(&s != nullptr) ? s.getBuffer() : nullptr,
|
||||
(&s != nullptr) ? s.len() : 0
|
||||
}));
|
||||
}
|
||||
|
||||
// Send commands
|
||||
// Power On/Off
|
||||
void ZigbeeHuePower(uint16_t shortaddr, bool power) {
|
||||
zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0006, power ? 1 : 0, "");
|
||||
ZigbeeSendHue(shortaddr, 0x0006, power ? 1 : 0, *(SBuffer*)nullptr);
|
||||
// zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0006, power ? 1 : 0, "");
|
||||
zigbee_devices.getShortAddr(shortaddr).setPower(power, 0);
|
||||
}
|
||||
|
||||
// Dimmer
|
||||
void ZigbeeHueDimmer(uint16_t shortaddr, uint8_t dimmer) {
|
||||
if (dimmer > 0xFE) { dimmer = 0xFE; }
|
||||
char param[8];
|
||||
snprintf_P(param, sizeof(param), PSTR("%02X0A00"), dimmer);
|
||||
zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0008, 0x04, param);
|
||||
SBuffer s(4);
|
||||
s.add8(dimmer);
|
||||
s.add16(0x000A); // transition time = 1s
|
||||
ZigbeeSendHue(shortaddr, 0x0008, 0x04, s);
|
||||
// char param[8];
|
||||
// snprintf_P(param, sizeof(param), PSTR("%02X0A00"), dimmer);
|
||||
// zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0008, 0x04, param);
|
||||
zigbee_devices.getLight(shortaddr).setDimmer(dimmer);
|
||||
}
|
||||
|
||||
// CT
|
||||
void ZigbeeHueCT(uint16_t shortaddr, uint16_t ct) {
|
||||
if (ct > 0xFEFF) { ct = 0xFEFF; }
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("ZigbeeHueCT 0x%04X - %d"), shortaddr, ct);
|
||||
char param[12];
|
||||
snprintf_P(param, sizeof(param), PSTR("%02X%02X0A00"), ct & 0xFF, ct >> 8);
|
||||
uint8_t colormode = 2; // "ct"
|
||||
zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x0A, param);
|
||||
// AddLog(LOG_LEVEL_INFO, PSTR("ZigbeeHueCT 0x%04X - %d"), shortaddr, ct);
|
||||
SBuffer s(4);
|
||||
s.add16(ct);
|
||||
s.add16(0x000A); // transition time = 1s
|
||||
ZigbeeSendHue(shortaddr, 0x0300, 0x0A, s);
|
||||
// char param[12];
|
||||
// snprintf_P(param, sizeof(param), PSTR("%02X%02X0A00"), ct & 0xFF, ct >> 8);
|
||||
// zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x0A, param);
|
||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
||||
light.setColorMode(colormode);
|
||||
light.setColorMode(2); // "ct"
|
||||
light.setCT(ct);
|
||||
}
|
||||
|
||||
// XY
|
||||
void ZigbeeHueXY(uint16_t shortaddr, uint16_t x, uint16_t y) {
|
||||
char param[16];
|
||||
if (x > 0xFEFF) { x = 0xFEFF; }
|
||||
if (y > 0xFEFF) { y = 0xFEFF; }
|
||||
snprintf_P(param, sizeof(param), PSTR("%02X%02X%02X%02X0A00"), x & 0xFF, x >> 8, y & 0xFF, y >> 8);
|
||||
uint8_t colormode = 1; // "xy"
|
||||
zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x07, param);
|
||||
SBuffer s(8);
|
||||
s.add16(x);
|
||||
s.add16(y);
|
||||
s.add16(0x000A); // transition time = 1s
|
||||
ZigbeeSendHue(shortaddr, 0x0300, 0x07, s);
|
||||
// char param[16];
|
||||
// snprintf_P(param, sizeof(param), PSTR("%02X%02X%02X%02X0A00"), x & 0xFF, x >> 8, y & 0xFF, y >> 8);
|
||||
// uint8_t colormode = 1; // "xy"
|
||||
// zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x07, param);
|
||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
||||
light.setColorMode(colormode);
|
||||
light.setColorMode(1); // "xy"
|
||||
light.setX(x);
|
||||
light.setY(y);
|
||||
}
|
||||
|
||||
// HueSat
|
||||
void ZigbeeHueHS(uint16_t shortaddr, uint16_t hue, uint8_t sat) {
|
||||
char param[16];
|
||||
uint8_t hue8 = changeUIntScale(hue, 0, 360, 0, 254);
|
||||
if (sat > 0xFE) { sat = 0xFE; }
|
||||
snprintf_P(param, sizeof(param), PSTR("%02X%02X0000"), hue8, sat);
|
||||
uint8_t colormode = 0; // "hs"
|
||||
zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x06, param);
|
||||
SBuffer s(4);
|
||||
s.add8(hue);
|
||||
s.add8(sat);
|
||||
s.add16(0);
|
||||
ZigbeeSendHue(shortaddr, 0x0300, 0x06, s);
|
||||
// char param[16];
|
||||
// snprintf_P(param, sizeof(param), PSTR("%02X%02X0000"), hue8, sat);
|
||||
// uint8_t colormode = 0; // "hs"
|
||||
// zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x06, param);
|
||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
||||
light.setColorMode(colormode);
|
||||
light.setColorMode(0); // "hs"
|
||||
light.setSat(sat);
|
||||
light.setHue(hue);
|
||||
}
|
||||
|
|
|
@ -436,9 +436,7 @@ void restoreDumpAllDevices(void) {
|
|||
for (const auto & device : zigbee_devices.getDevices()) {
|
||||
const SBuffer buf = hibernateDevicev2(device);
|
||||
if (buf.len() > 0) {
|
||||
char hex_char[buf.len()*2+2];
|
||||
Response_P(PSTR("{\"" D_PRFX_ZB D_CMND_ZIGBEE_RESTORE "\":\"ZbRestore %s\"}"),
|
||||
ToHex_P(buf.buf(0), buf.len(), hex_char, sizeof(hex_char)));
|
||||
Response_P(PSTR("{\"" D_PRFX_ZB D_CMND_ZIGBEE_RESTORE "\":\"ZbRestore %_B\"}"), &buf);
|
||||
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_PRFX_ZB D_CMND_ZIGBEE_DATA));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#ifdef USE_ZIGBEE
|
||||
#ifdef USE_ZIGBEE_EZSP
|
||||
|
||||
#define Z_EEPROM_DEBUG
|
||||
// #define Z_EEPROM_DEBUG
|
||||
|
||||
// The EEPROM is 64KB in size with individually writable bytes.
|
||||
// They are conveniently organized in pages of 128 bytes to accelerate
|
||||
|
@ -291,7 +291,7 @@ bool ZFS::findFileEntry(uint32_t name, ZFS_File_Entry & entry, uint8_t * _entry_
|
|||
#ifdef Z_EEPROM_DEBUG
|
||||
// {
|
||||
// char hex_char[(sizeof(ZFS_File_Entry) * 2) + 2];
|
||||
// AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Read entry %d at address 0x%04X contains %s"), entry_idx, entry_addr, ToHex_P((uint8_t*)&entry, sizeof(entry), hex_char, sizeof(hex_char)));
|
||||
// AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Read entry %d at address 0x%04X contains %*_H"), entry_idx, entry_addr, sizeof(entry), &entry);
|
||||
// }
|
||||
#endif
|
||||
if (entry.name == name) {
|
||||
|
|
|
@ -89,8 +89,7 @@ int32_t hydrateSingleDevice(const SBuffer & buf, size_t start, size_t len) {
|
|||
#ifdef Z_EEPROM_DEBUG
|
||||
{
|
||||
if (segment_len > 3) {
|
||||
char hex_char[((segment_len+1) * 2) + 2];
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "ZbData 0x%04X,%s"), shortaddr, ToHex_P(buf.buf(start+3), segment_len+1-3, hex_char, sizeof(hex_char)));
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "ZbData 0x%04X,%*_H"), shortaddr, segment_len+1-3, buf.buf(start+3));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -182,16 +181,14 @@ SBuffer hibernateDeviceData(const struct Z_Device & device, bool mqtt = false) {
|
|||
buf.set8(0, buf.len() - 1);
|
||||
|
||||
{
|
||||
size_t buf_len = buf.len() - 3;
|
||||
char hex[2*buf_len + 1];
|
||||
// skip first 3 bytes
|
||||
ToHex_P(buf.buf(3), buf_len, hex, sizeof(hex));
|
||||
size_t buf_len = buf.len() - 3;
|
||||
|
||||
if (mqtt) {
|
||||
Response_P(PSTR("{\"" D_PRFX_ZB D_CMND_ZIGBEE_DATA "\":\"ZbData 0x%04X,%s\"}"), device.shortaddr, hex);
|
||||
Response_P(PSTR("{\"" D_PRFX_ZB D_CMND_ZIGBEE_DATA "\":\"ZbData 0x%04X,%*_H\"}"), device.shortaddr, buf_len, buf.buf(3));
|
||||
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_PRFX_ZB D_CMND_ZIGBEE_DATA));
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "ZbData 0x%04X,%s"), device.shortaddr, hex);
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "ZbData 0x%04X,%*_H"), device.shortaddr, buf_len, buf.buf(3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -723,8 +723,6 @@ public:
|
|||
|
||||
|
||||
void log(void) {
|
||||
char hex_char[_payload.len()*2+2];
|
||||
ToHex_P((unsigned char*)_payload.getBuffer(), _payload.len(), hex_char, sizeof(hex_char));
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEEZCL_RECEIVED "\":{"
|
||||
"\"groupid\":%d," "\"clusterid\":\"0x%04X\"," "\"srcaddr\":\"0x%04X\","
|
||||
"\"srcendpoint\":%d," "\"dstendpoint\":%d," "\"wasbroadcast\":%d,"
|
||||
|
@ -732,14 +730,14 @@ public:
|
|||
"\"fc\":\"0x%02X\","
|
||||
"\"frametype\":%d,\"direction\":%d,\"disableresp\":%d,"
|
||||
"\"manuf\":\"0x%04X\",\"transact\":%d,"
|
||||
"\"cmdid\":\"0x%02X\",\"payload\":\"%s\"}}"),
|
||||
"\"cmdid\":\"0x%02X\",\"payload\":\"%_B\"}}"),
|
||||
_groupaddr, _cluster_id, _srcaddr,
|
||||
_srcendpoint, _dstendpoint, _wasbroadcast,
|
||||
_linkquality, _securityuse, _seqnumber,
|
||||
_frame_control,
|
||||
_frame_control.b.frame_type, _frame_control.b.direction, _frame_control.b.disable_def_resp,
|
||||
_manuf_code, _transact_seq, _cmd_id,
|
||||
hex_char);
|
||||
&_payload);
|
||||
if (Settings.flag3.tuya_serial_mqtt_publish) {
|
||||
MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR));
|
||||
} else {
|
||||
|
|
|
@ -415,16 +415,16 @@ int32_t ZNP_ReceiveCheckVersion(int32_t res, SBuffer &buf) {
|
|||
int32_t EZ_ReceiveCheckVersion(int32_t res, SBuffer &buf) {
|
||||
uint8_t protocol_version = buf.get8(2);
|
||||
uint8_t stack_type = buf.get8(3);
|
||||
uint16_t stack_version = buf.get16(4);
|
||||
zigbee.ezsp_version = buf.get16(4);
|
||||
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{"
|
||||
"\"Status\":%d,\"Version\":\"%d.%d.%d.%d\",\"Protocol\":%d"
|
||||
",\"Stack\":%d}}"),
|
||||
ZIGBEE_STATUS_EZ_VERSION,
|
||||
(stack_version & 0xF000) >> 12,
|
||||
(stack_version & 0x0F00) >> 8,
|
||||
(stack_version & 0x00F0) >> 4,
|
||||
stack_version & 0x000F,
|
||||
(zigbee.ezsp_version & 0xF000) >> 12,
|
||||
(zigbee.ezsp_version & 0x0F00) >> 8,
|
||||
(zigbee.ezsp_version & 0x00F0) >> 4,
|
||||
zigbee.ezsp_version & 0x000F,
|
||||
protocol_version,
|
||||
stack_type
|
||||
);
|
||||
|
@ -432,7 +432,7 @@ int32_t EZ_ReceiveCheckVersion(int32_t res, SBuffer &buf) {
|
|||
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE));
|
||||
|
||||
if (0x08 == protocol_version) {
|
||||
if ((stack_version & 0xFF00) == 0x6700) {
|
||||
if ((zigbee.ezsp_version & 0xFF00) == 0x6700) {
|
||||
// If v6.7 there is a bug so we need to change the response
|
||||
ZBW(ZBR_SET_OK2, 0x00, 0x00 /*high*/, 0x00 /*ok*/)
|
||||
}
|
||||
|
|
|
@ -222,9 +222,6 @@ void ZigbeeInputLoop(void) {
|
|||
|
||||
uint32_t frame_len = zigbee_buffer->len();
|
||||
if (frame_complete || (frame_len && (millis() > (zigbee_polling_window + ZIGBEE_POLLING)))) {
|
||||
char hex_char[frame_len * 2 + 2];
|
||||
ToHex_P((unsigned char*)zigbee_buffer->getBuffer(), zigbee_buffer->len(), hex_char, sizeof(hex_char));
|
||||
|
||||
// AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Bytes follow_read_metric = %0d"), ZigbeeSerial->getLoopReadMetric());
|
||||
if ((frame_complete) && (frame_len >= 3)) {
|
||||
// frame received and has at least 3 bytes (without EOF), checking CRC
|
||||
|
@ -246,7 +243,7 @@ void ZigbeeInputLoop(void) {
|
|||
// remove 2 last bytes
|
||||
|
||||
if (crc_received != crc) {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEE_EZSP_RECEIVED ": bad crc (received 0x%04X, computed 0x%04X) %s"), crc_received, crc, hex_char);
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEE_EZSP_RECEIVED ": bad crc (received 0x%04X, computed 0x%04X) %_B"), crc_received, crc, &zigbee_buffer);
|
||||
} else {
|
||||
// copy buffer
|
||||
SBuffer ezsp_buffer = zigbee_buffer->subBuffer(0, frame_len - 2); // CRC
|
||||
|
@ -262,14 +259,13 @@ void ZigbeeInputLoop(void) {
|
|||
}
|
||||
}
|
||||
|
||||
ToHex_P((unsigned char*)ezsp_buffer.getBuffer(), ezsp_buffer.len(), hex_char, sizeof(hex_char));
|
||||
AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "{\"" D_JSON_ZIGBEE_EZSP_RECEIVED "2\":\"%s\"}"), hex_char);
|
||||
AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "{\"" D_JSON_ZIGBEE_EZSP_RECEIVED "2\":\"%_B\"}"), &ezsp_buffer);
|
||||
// now process the message
|
||||
ZigbeeProcessInputRaw(ezsp_buffer);
|
||||
}
|
||||
} else {
|
||||
// the buffer timed-out, print error and discard
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEE_EZSP_RECEIVED ": time-out, discarding %s, %d"), hex_char);
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEE_EZSP_RECEIVED ": time-out, discarding %s, %_B"), &zigbee_buffer);
|
||||
}
|
||||
zigbee_buffer->setLen(0); // empty buffer
|
||||
escape = false;
|
||||
|
@ -352,9 +348,7 @@ void ZigbeeZNPSend(const uint8_t *msg, size_t len) {
|
|||
//AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend FCS %02X"), fcs);
|
||||
}
|
||||
// Now send a MQTT message to report the sent message
|
||||
char hex_char[(len * 2) + 2];
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZNPSENT " %s"),
|
||||
ToHex_P(msg, len, hex_char, sizeof(hex_char)));
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZNPSENT " %*_H"), len, msg);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -486,17 +480,13 @@ void ZigbeeEZSPSendRaw(const uint8_t *msg, size_t len, bool send_cancel) {
|
|||
}
|
||||
|
||||
// Now send a MQTT message to report the sent message
|
||||
char hex_char[(len * 2) + 2];
|
||||
AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEE_EZSP_SENT_RAW " %s"),
|
||||
ToHex_P(msg, len, hex_char, sizeof(hex_char)));
|
||||
AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEE_EZSP_SENT_RAW " %*_H"), len, msg);
|
||||
}
|
||||
|
||||
// Send an EZSP command and data
|
||||
// Ex: Version with min v8 = 000008
|
||||
void ZigbeeEZSPSendCmd(const uint8_t *msg, size_t len) {
|
||||
char hex_char[len*2 + 2];
|
||||
ToHex_P(msg, len, hex_char, sizeof(hex_char));
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "ZbEZSPSend %s"), hex_char);
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "ZbEZSPSend %*_H"), len, msg);
|
||||
|
||||
SBuffer cmd(len+3); // prefix with seq number (1 byte) and frame control bytes (2 bytes)
|
||||
|
||||
|
@ -567,11 +557,8 @@ void ZigbeeProcessInputEZSP(SBuffer &buf) {
|
|||
}
|
||||
buf.setLen(buf.len() - 3);
|
||||
|
||||
char hex_char[buf.len()*2 + 2];
|
||||
|
||||
// log message
|
||||
ToHex_P((unsigned char*)buf.getBuffer(), buf.len(), hex_char, sizeof(hex_char));
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_EZSP_RECEIVED "\":\"%s\"}"), hex_char);
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_EZSP_RECEIVED "\":\"%_B\"}"), &buf);
|
||||
if (Settings.flag3.tuya_serial_mqtt_publish) {
|
||||
MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR));
|
||||
} else {
|
||||
|
|
|
@ -264,9 +264,7 @@ bool ZigbeeUploadBootloaderPrompt(void) {
|
|||
}
|
||||
|
||||
if (buf_len) {
|
||||
char hex_char[256];
|
||||
ToHex_P(serial_buffer, buf_len, hex_char, 256);
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("XMD: Rcvd %s"), hex_char);
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("XMD: Rcvd %*_H"), buf_len, serial_buffer);
|
||||
}
|
||||
|
||||
return ((4 == ZbUpload.byte_counter) && (millis() > XModem.flush_delay));
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
#include "UnishoxStrings.h"
|
||||
|
||||
const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
|
||||
// SetOption synonyms
|
||||
D_SO_ZIGBEE_NAMEKEY "|" D_SO_ZIGBEE_DEVICETOPIC "|" D_SO_ZIGBEE_NOPREFIX "|" D_SO_ZIGBEE_ENDPOINTSUFFIX "|" D_SO_ZIGBEE_NOAUTOBIND "|"
|
||||
D_SO_ZIGBEE_NAMETOPIC "|"
|
||||
#ifdef USE_ZIGBEE_ZNP
|
||||
D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEEZNPRECEIVE "|"
|
||||
#endif // USE_ZIGBEE_ZNP
|
||||
|
@ -39,6 +42,12 @@ const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
|
|||
D_CMND_ZIGBEE_CONFIG "|" D_CMND_ZIGBEE_DATA
|
||||
;
|
||||
|
||||
const uint8_t kZbSynonyms[] PROGMEM = {
|
||||
6, // number of synonyms
|
||||
83, 89, 100, 101, 110,
|
||||
112,
|
||||
};
|
||||
|
||||
void (* const ZigbeeCommand[])(void) PROGMEM = {
|
||||
#ifdef USE_ZIGBEE_ZNP
|
||||
&CmndZbZNPSend, &CmndZbZNPReceive,
|
||||
|
@ -183,23 +192,7 @@ void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint,
|
|||
}
|
||||
}
|
||||
|
||||
if ((0 == endpoint) && (BAD_SHORTADDR != shortaddr)) {
|
||||
// endpoint is not specified, let's try to find it from shortAddr, unless it's a group address
|
||||
endpoint = zigbee_devices.findFirstEndpoint(shortaddr);
|
||||
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: guessing endpoint 0x%02X"), endpoint);
|
||||
}
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: shortaddr 0x%04X, groupaddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %s"),
|
||||
shortaddr, groupaddr, cluster, endpoint, cmd, param);
|
||||
|
||||
if ((0 == endpoint) && (BAD_SHORTADDR != shortaddr)) { // endpoint null is ok for group address
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("ZbSend: unspecified endpoint"));
|
||||
return;
|
||||
}
|
||||
|
||||
// everything is good, we can send the command
|
||||
|
||||
uint8_t seq = zigbee_devices.getNextSeqNumber(shortaddr);
|
||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
||||
zigbeeZCLSendCmd(ZigbeeZCLSendMessage({
|
||||
shortaddr,
|
||||
groupaddr,
|
||||
cluster /*cluster*/,
|
||||
|
@ -209,14 +202,37 @@ void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint,
|
|||
clusterSpecific /* not cluster specific */,
|
||||
true /* response */,
|
||||
false /* discover route */,
|
||||
seq, /* zcl transaction id */
|
||||
0, /* zcl transaction id */
|
||||
buf.getBuffer(), buf.len()
|
||||
}));
|
||||
}
|
||||
|
||||
void zigbeeZCLSendCmd(const class ZigbeeZCLSendMessage &msg_const) {
|
||||
ZigbeeZCLSendMessage msg = msg_const; // copy to a modifiable variable
|
||||
|
||||
if ((0 == msg.endpoint) && (BAD_SHORTADDR != msg.shortaddr)) {
|
||||
// endpoint is not specified, let's try to find it from shortAddr, unless it's a group address
|
||||
msg.endpoint = zigbee_devices.findFirstEndpoint(msg.shortaddr);
|
||||
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: guessing endpoint 0x%02X"), endpoint);
|
||||
}
|
||||
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: shortaddr 0x%04X, groupaddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %*_H"),
|
||||
msg.shortaddr, msg.groupaddr, msg.cluster, msg.endpoint, msg.cmd, msg.len, msg.msg);
|
||||
|
||||
if ((0 == msg.endpoint) && (BAD_SHORTADDR != msg.shortaddr)) { // endpoint null is ok for group address
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("ZbSend: unspecified endpoint"));
|
||||
return;
|
||||
}
|
||||
|
||||
// everything is good, we can send the command
|
||||
|
||||
msg.transacId = zigbee_devices.getNextSeqNumber(msg.shortaddr);
|
||||
ZigbeeZCLSend_Raw(msg);
|
||||
// now set the timer, if any, to read back the state later
|
||||
if (clusterSpecific) {
|
||||
if (msg.clusterSpecific) {
|
||||
if (!Settings.flag5.zb_disable_autoquery) {
|
||||
// read back attribute value unless it is disabled
|
||||
sendHueUpdate(shortaddr, groupaddr, cluster, endpoint);
|
||||
sendHueUpdate(msg.shortaddr, msg.groupaddr, msg.cluster, msg.endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -463,7 +479,7 @@ void ZbSendSend(class JsonParserToken val_cmd, uint16_t device, uint16_t groupad
|
|||
const char *cmd_s = ""; // pointer to payload string
|
||||
bool clusterSpecific = true;
|
||||
|
||||
static char delim[] = ", "; // delimiters for parameters
|
||||
static const char delim[] = ", "; // delimiters for parameters
|
||||
// probe the type of the argument
|
||||
// If JSON object, it's high level commands
|
||||
// If String, it's a low level command
|
||||
|
@ -2175,7 +2191,7 @@ bool Xdrv23(uint8_t function)
|
|||
ZigbeeInit();
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kZbCommands, ZigbeeCommand);
|
||||
result = DecodeCommand(kZbCommands, ZigbeeCommand, kZbSynonyms);
|
||||
break;
|
||||
case FUNC_SAVE_BEFORE_RESTART:
|
||||
#ifdef USE_ZIGBEE_EZSP
|
||||
|
|
|
@ -90,9 +90,7 @@ void TCPLoop(void)
|
|||
}
|
||||
}
|
||||
if (buf_len > 0) {
|
||||
char hex_char[TCP_BRIDGE_BUF_SIZE+1];
|
||||
ToHex_P(tcp_buf, buf_len, hex_char, 256);
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_TCP "from MCU: %s"), hex_char);
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_TCP "from MCU: %*_H"), buf_len, tcp_buf);
|
||||
|
||||
for (uint32_t i=0; i<ARRAY_SIZE(client_tcp); i++) {
|
||||
WiFiClient &client = client_tcp[i];
|
||||
|
@ -112,9 +110,7 @@ void TCPLoop(void)
|
|||
}
|
||||
}
|
||||
if (buf_len > 0) {
|
||||
char hex_char[TCP_BRIDGE_BUF_SIZE+1];
|
||||
ToHex_P(tcp_buf, buf_len, hex_char, 256);
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_TCP "to MCU/%d: %s"), i+1, hex_char);
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_TCP "to MCU/%d: %*_H"), i+1, buf_len, tcp_buf);
|
||||
TCPSerial->write(tcp_buf, buf_len);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -279,7 +279,7 @@ const char * getStateString(int state);
|
|||
//int SafeAddLog_P(uint32_t loglevel, PGM_P formatP, ...);
|
||||
|
||||
static void BLEDiag();
|
||||
const char *getAlias(uint8_t *addr);
|
||||
const char *getAlias(const uint8_t *addr);
|
||||
//void BLEAliasMqttList();
|
||||
void BLEAliasListResp();
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -320,7 +320,7 @@ static void BLEGenNotifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, ui
|
|||
void BLEPostAdvert(ble_advertisment_t *Advertisment);
|
||||
static void BLEPostMQTTSeenDevices(int type);
|
||||
|
||||
static void BLEShow(bool json);
|
||||
static void BLEShowStats();
|
||||
static void BLEPostMQTT(bool json);
|
||||
static void BLEStartOperationTask();
|
||||
|
||||
|
@ -390,7 +390,7 @@ uint8_t BLEAliasListTrigger = 0;
|
|||
// triggers send for ALL operations known about
|
||||
uint8_t BLEPostMQTTTrigger = 0;
|
||||
int BLEMaxAge = 60*10; // 10 minutes
|
||||
int BLEAddressFilter = 3;
|
||||
int BLEAddressFilter = 0;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
@ -2181,6 +2181,7 @@ static void BLEEverySecond(bool restart){
|
|||
|
||||
if (BLEPublishDevices){
|
||||
BLEPostMQTTSeenDevices(BLEPublishDevices);
|
||||
BLEShowStats();
|
||||
BLEPublishDevices = 0;
|
||||
}
|
||||
|
||||
|
@ -2403,7 +2404,7 @@ static const char *noAlias = PSTR("");
|
|||
|
||||
////////////////////////////////////////////
|
||||
// use to display the alias name if required
|
||||
const char *getAlias(uint8_t *addr){
|
||||
const char *getAlias(const uint8_t *addr){
|
||||
if (!addr){
|
||||
return noAlias;
|
||||
}
|
||||
|
@ -3209,26 +3210,15 @@ static void mainThreadOpCallbacks() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static void BLEShow(bool json)
|
||||
{
|
||||
if (json){
|
||||
#ifdef BLE_ESP32_DEBUG
|
||||
if (BLEDebugMode > 0) AddLog(LOG_LEVEL_INFO,PSTR("BLE: show json %d"),json);
|
||||
#endif
|
||||
uint32_t totalCount = BLEAdvertisment.totalCount;
|
||||
uint32_t deviceCount = seenDevices.size();
|
||||
|
||||
ResponseAppend_P(PSTR(",\"BLE\":{\"scans\":%u,\"adverts\":%u,\"devices\":%u,\"resets\":%u}"), BLEScanCount, totalCount, deviceCount, BLEResets);
|
||||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
else {
|
||||
//WSContentSend_PD(HTTP_MI32, i+1,stemp,MIBLEsensors.size());
|
||||
}
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
static void BLEShowStats(){
|
||||
uint32_t totalCount = BLEAdvertisment.totalCount;
|
||||
uint32_t deviceCount = seenDevices.size();
|
||||
ResponseTime_P(PSTR(""));
|
||||
ResponseAppend_P(PSTR(",\"BLE\":{\"scans\":%u,\"adverts\":%u,\"devices\":%u,\"resets\":%u}}"), BLEScanCount, totalCount, deviceCount, BLEResets);
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR("BLE"), 0);
|
||||
}
|
||||
|
||||
|
||||
/*void BLEAliasMqttList(){
|
||||
ResponseTime_P(PSTR(",\"BLEAlias\":["));
|
||||
for (int i = 0; i < aliases.size(); i++){
|
||||
|
@ -3495,7 +3485,6 @@ bool Xdrv52(uint8_t function)
|
|||
result = DecodeCommand(BLE_ESP32::kBLE_Commands, BLE_ESP32::BLE_Commands);
|
||||
break;
|
||||
case FUNC_JSON_APPEND:
|
||||
BLE_ESP32::BLEShow(1);
|
||||
break;
|
||||
|
||||
// next second, we will publish to our MQTT topic.
|
||||
|
@ -3510,10 +3499,6 @@ bool Xdrv52(uint8_t function)
|
|||
case FUNC_WEB_ADD_HANDLER:
|
||||
WebServer_on(PSTR("/" WEB_HANDLE_BLE), BLE_ESP32::HandleBleConfiguration);
|
||||
break;
|
||||
|
||||
case FUNC_WEB_SENSOR:
|
||||
BLE_ESP32::BLEShow(0);
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -435,8 +435,6 @@ void solaxX1Show(bool json)
|
|||
char pv2_power[33];
|
||||
dtostrfd(solaxX1.dc2_power, Settings.flag2.wattage_resolution, pv2_power);
|
||||
#endif
|
||||
char temperature[33];
|
||||
dtostrfd(solaxX1.temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
char runtime[33];
|
||||
dtostrfd(solaxX1.runtime_total, 0, runtime);
|
||||
char status[33];
|
||||
|
@ -450,12 +448,12 @@ void solaxX1Show(bool json)
|
|||
ResponseAppend_P(PSTR(",\"" D_JSON_PV2_VOLTAGE "\":%s,\"" D_JSON_PV2_CURRENT "\":%s,\"" D_JSON_PV2_POWER "\":%s"),
|
||||
pv2_voltage, pv2_current, pv2_power);
|
||||
#endif
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_RUNTIME "\":%s,\"" D_JSON_STATUS "\":\"%s\",\"" D_JSON_ERROR "\":%d"),
|
||||
temperature, runtime, status, solaxX1.errorCode);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%*_f,\"" D_JSON_RUNTIME "\":%s,\"" D_JSON_STATUS "\":\"%s\",\"" D_JSON_ERROR "\":%d"),
|
||||
Settings.flag2.temperature_resolution, &solaxX1.temperature, runtime, status, solaxX1.errorCode);
|
||||
|
||||
#ifdef USE_DOMOTICZ
|
||||
// Avoid bad temperature report at beginning of the day (spikes of 1200 celsius degrees)
|
||||
if (0 == TasmotaGlobal.tele_period && solaxX1.temperature < 100) { DomoticzSensor(DZ_TEMP, temperature); }
|
||||
if (0 == TasmotaGlobal.tele_period && solaxX1.temperature < 100) { DomoticzFloatSensor(DZ_TEMP, solaxX1.temperature); }
|
||||
#endif // USE_DOMOTICZ
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
|
@ -464,7 +462,7 @@ void solaxX1Show(bool json)
|
|||
#ifdef SOLAXX1_PV2
|
||||
WSContentSend_PD(HTTP_SNS_solaxX1_DATA2, pv2_voltage, pv2_current, pv2_power);
|
||||
#endif
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, D_SOLAX_X1, temperature, TempUnit());
|
||||
WSContentSend_Temp(D_SOLAX_X1, solaxX1.temperature);
|
||||
char errorCodeString[33];
|
||||
WSContentSend_PD(HTTP_SNS_solaxX1_DATA3, runtime, status,
|
||||
GetTextIndexed(errorCodeString, sizeof(errorCodeString), solaxX1_ParseErrorCode(solaxX1.errorCode), kSolaxError));
|
||||
|
|
|
@ -268,14 +268,11 @@ bool Bl0940Command(void) {
|
|||
}
|
||||
|
||||
void Bl0940Show(bool json) {
|
||||
char temperature[33];
|
||||
dtostrfd(Bl0940.temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
|
||||
if (json) {
|
||||
ResponseAppend_P(JSON_SNS_TEMP, "BL0940", temperature);
|
||||
ResponseAppend_P(JSON_SNS_F_TEMP, "BL0940", Settings.flag2.temperature_resolution, &Bl0940.temperature);
|
||||
if (0 == TasmotaGlobal.tele_period) {
|
||||
#ifdef USE_DOMOTICZ
|
||||
DomoticzSensor(DZ_TEMP, temperature);
|
||||
DomoticzFloatSensor(DZ_TEMP, Bl0940.temperature);
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_KNX
|
||||
KnxSensor(KNX_TEMPERATURE, Bl0940.temperature);
|
||||
|
@ -283,8 +280,9 @@ void Bl0940Show(bool json) {
|
|||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, "", temperature, TempUnit());
|
||||
WSContentSend_Temp("", Bl0940.temperature);
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -457,15 +457,12 @@ void AdcShow(bool json) {
|
|||
break;
|
||||
}
|
||||
case ADC_TEMP: {
|
||||
char temperature[33];
|
||||
dtostrfd(Adc[idx].temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
|
||||
if (json) {
|
||||
AdcShowContinuation(&jsonflg);
|
||||
ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "%s\":%s"), adc_idx, temperature);
|
||||
ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "%s\":%*_f"), adc_idx, Settings.flag2.temperature_resolution, &Adc[idx].temperature);
|
||||
if ((0 == TasmotaGlobal.tele_period) && (!domo_flag[ADC_TEMP])) {
|
||||
#ifdef USE_DOMOTICZ
|
||||
DomoticzSensor(DZ_TEMP, temperature);
|
||||
DomoticzFloatSensor(DZ_TEMP, Adc[idx].temperature);
|
||||
domo_flag[ADC_TEMP] = true;
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_KNX
|
||||
|
@ -474,7 +471,7 @@ void AdcShow(bool json) {
|
|||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, adc_name, temperature, TempUnit());
|
||||
WSContentSend_Temp(adc_name, Adc[idx].temperature);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -499,9 +499,6 @@ void Ds18x20Show(bool json)
|
|||
uint8_t index = ds18x20_sensor[i].index;
|
||||
|
||||
if (ds18x20_sensor[index].valid) { // Check for valid temperature
|
||||
char temperature[33];
|
||||
dtostrfd(ds18x20_sensor[index].temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
|
||||
Ds18x20Name(i);
|
||||
|
||||
if (json) {
|
||||
|
@ -509,10 +506,11 @@ void Ds18x20Show(bool json)
|
|||
for (uint32_t j = 0; j < 6; j++) {
|
||||
sprintf(address+2*j, "%02X", ds18x20_sensor[index].address[6-j]); // Skip sensor type and crc
|
||||
}
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ID "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%s}"), ds18x20_types, address, temperature);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ID "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%*_f}"),
|
||||
ds18x20_types, address, Settings.flag2.temperature_resolution, &ds18x20_sensor[index].temperature);
|
||||
#ifdef USE_DOMOTICZ
|
||||
if ((0 == TasmotaGlobal.tele_period) && (0 == i)) {
|
||||
DomoticzSensor(DZ_TEMP, temperature);
|
||||
DomoticzFloatSensor(DZ_TEMP, ds18x20_sensor[index].temperature);
|
||||
}
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_KNX
|
||||
|
@ -522,7 +520,7 @@ void Ds18x20Show(bool json)
|
|||
#endif // USE_KNX
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, ds18x20_types, temperature, TempUnit());
|
||||
WSContentSend_Temp(ds18x20_types, ds18x20_sensor[index].temperature);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,9 +200,6 @@ void Ds18x20Show(bool json)
|
|||
uint8_t dsxflg = 0;
|
||||
for (uint32_t i = 0; i < ds18x20_sensors; i++) {
|
||||
if (Ds18x20Read(i, t)) { // Check if read failed
|
||||
char temperature[33];
|
||||
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
|
||||
|
||||
Ds18x20Name(i);
|
||||
|
||||
if (json) {
|
||||
|
@ -210,11 +207,12 @@ void Ds18x20Show(bool json)
|
|||
for (uint32_t j = 0; j < 6; j++) {
|
||||
sprintf(address+2*j, "%02X", ds18x20_address[ds18x20_index[i]][6-j]); // Skip sensor type and crc
|
||||
}
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ID "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%s}"), ds18x20_types, address, temperature);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ID "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%*_f}"),
|
||||
ds18x20_types, address, Settings.flag2.temperature_resolution, &t);
|
||||
dsxflg++;
|
||||
#ifdef USE_DOMOTICZ
|
||||
if ((0 == TasmotaGlobal.tele_period) && (1 == dsxflg)) {
|
||||
DomoticzSensor(DZ_TEMP, temperature);
|
||||
DomoticzFloatSensor(DZ_TEMP, t);
|
||||
}
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_KNX
|
||||
|
@ -224,7 +222,7 @@ void Ds18x20Show(bool json)
|
|||
#endif // USE_KNX
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, ds18x20_types, temperature, TempUnit());
|
||||
WSContentSend_Temp(ds18x20_types, t);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
|
|
@ -527,8 +527,6 @@ void BmpShow(bool json)
|
|||
snprintf_P(name, sizeof(name), PSTR("%s%c%02X"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address); // BMXXXX-XX
|
||||
}
|
||||
|
||||
char temperature[33];
|
||||
dtostrfd(bmp_temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
char pressure[33];
|
||||
dtostrfd(bmp_pressure, Settings.flag2.pressure_resolution, pressure);
|
||||
char sea_pressure[33];
|
||||
|
@ -554,16 +552,16 @@ void BmpShow(bool json)
|
|||
char json_gas[40];
|
||||
snprintf_P(json_gas, sizeof(json_gas), PSTR(",\"" D_JSON_GAS "\":%s"), gas_resistance);
|
||||
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s%s}"),
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%*_f%s,\"" D_JSON_PRESSURE "\":%s%s%s}"),
|
||||
name,
|
||||
temperature,
|
||||
Settings.flag2.temperature_resolution, &bmp_temperature,
|
||||
(bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "",
|
||||
pressure,
|
||||
(Settings.altitude != 0) ? json_sealevel : "",
|
||||
(bmp_sensors[bmp_idx].bmp_model >= 3) ? json_gas : "");
|
||||
#else
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s}"),
|
||||
name, temperature, (bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : "");
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%*_f%s,\"" D_JSON_PRESSURE "\":%s%s}"),
|
||||
name, Settings.flag2.temperature_resolution, &bmp_temperature, (bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : "");
|
||||
#endif // USE_BME680
|
||||
|
||||
#ifdef USE_DOMOTICZ
|
||||
|
@ -584,7 +582,7 @@ void BmpShow(bool json)
|
|||
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, name, temperature, TempUnit());
|
||||
WSContentSend_Temp(name, bmp_temperature);
|
||||
if (bmp_sensors[bmp_idx].bmp_model >= 2) {
|
||||
WSContentSend_PD(HTTP_SNS_HUM, name, humidity);
|
||||
WSContentSend_PD(HTTP_SNS_DEW, name, dewpoint, TempUnit());
|
||||
|
|
|
@ -338,23 +338,22 @@ void MhzInit(void)
|
|||
void MhzShow(bool json)
|
||||
{
|
||||
char types[7] = "MHZ19B"; // MHZ19B for legacy reasons. Prefered is MHZ19
|
||||
char temperature[33];
|
||||
dtostrfd(mhz_temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
char model[3];
|
||||
GetTextIndexed(model, sizeof(model), mhz_type -1, kMhzModels);
|
||||
|
||||
if (json) {
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_MODEL "\":\"%s\",\"" D_JSON_CO2 "\":%d,\"" D_JSON_TEMPERATURE "\":%s}"), types, model, mhz_last_ppm, temperature);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_MODEL "\":\"%s\",\"" D_JSON_CO2 "\":%d,\"" D_JSON_TEMPERATURE "\":%*_f}"),
|
||||
types, model, mhz_last_ppm, Settings.flag2.temperature_resolution, &mhz_temperature);
|
||||
#ifdef USE_DOMOTICZ
|
||||
if (0 == TasmotaGlobal.tele_period) {
|
||||
DomoticzSensor(DZ_AIRQUALITY, mhz_last_ppm);
|
||||
DomoticzSensor(DZ_TEMP, temperature);
|
||||
DomoticzFloatSensor(DZ_TEMP, mhz_temperature);
|
||||
}
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_CO2, types, mhz_last_ppm);
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, types, temperature, TempUnit());
|
||||
WSContentSend_Temp(types, mhz_temperature);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,17 +85,15 @@ float LM75ADGetTemp(void)
|
|||
void LM75ADShow(bool json)
|
||||
{
|
||||
float t = LM75ADGetTemp();
|
||||
char temperature[33];
|
||||
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
|
||||
|
||||
if (json) {
|
||||
ResponseAppend_P(JSON_SNS_TEMP, "LM75AD", temperature);
|
||||
ResponseAppend_P(JSON_SNS_F_TEMP, "LM75AD", Settings.flag2.temperature_resolution, &t);
|
||||
#ifdef USE_DOMOTICZ
|
||||
if (0 == TasmotaGlobal.tele_period) DomoticzSensor(DZ_TEMP, temperature);
|
||||
if (0 == TasmotaGlobal.tele_period) DomoticzFloatSensor(DZ_TEMP, t);
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, "LM75AD", temperature, TempUnit());
|
||||
WSContentSend_Temp("LM75AD", t);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,8 +182,6 @@ void MPU_6050Show(bool json)
|
|||
MPU_6050PerformReading();
|
||||
|
||||
float tempConv = ConvertTemp(MPU_6050_temperature / 340.0 + 35.53);
|
||||
char temperature[33];
|
||||
dtostrfd(tempConv, Settings.flag2.temperature_resolution, temperature);
|
||||
char axis_ax[33];
|
||||
dtostrfd(MPU_6050_ax, Settings.flag2.axis_resolution, axis_ax);
|
||||
char axis_ay[33];
|
||||
|
@ -225,19 +223,19 @@ void MPU_6050Show(bool json)
|
|||
snprintf_P(json_ypr_p, sizeof(json_ypr_p), PSTR(",\"" D_JSON_PITCH "\":%s"), axis_pitch);
|
||||
char json_ypr_r[25];
|
||||
snprintf_P(json_ypr_r, sizeof(json_ypr_r), PSTR(",\"" D_JSON_ROLL "\":%s"), axis_roll);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s%s%s%s%s%s%s%s%s}"),
|
||||
D_SENSOR_MPU6050, temperature, json_axis_ax, json_axis_ay, json_axis_az, json_axis_gx, json_axis_gy, json_axis_gz,
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%*_f%s%s%s%s%s%s%s%s%s}"),
|
||||
D_SENSOR_MPU6050, Settings.flag2.temperature_resolution, &tempConv, json_axis_ax, json_axis_ay, json_axis_az, json_axis_gx, json_axis_gy, json_axis_gz,
|
||||
json_ypr_y, json_ypr_p, json_ypr_r);
|
||||
#else
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s%s%s%s%s%s}"),
|
||||
D_SENSOR_MPU6050, temperature, json_axis_ax, json_axis_ay, json_axis_az, json_axis_gx, json_axis_gy, json_axis_gz);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%*_f%s%s%s%s%s%s}"),
|
||||
D_SENSOR_MPU6050, Settings.flag2.temperature_resolution, &tempConv, json_axis_ax, json_axis_ay, json_axis_az, json_axis_gx, json_axis_gy, json_axis_gz);
|
||||
#endif // USE_MPU6050_DMP
|
||||
#ifdef USE_DOMOTICZ
|
||||
DomoticzSensor(DZ_TEMP, temperature);
|
||||
DomoticzFloatSensor(DZ_TEMP, tempConv);
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, D_SENSOR_MPU6050, temperature, TempUnit());
|
||||
WSContentSend_Temp(D_SENSOR_MPU6050, tempConv);
|
||||
WSContentSend_PD(HTTP_SNS_AXIS, axis_ax, axis_ay, axis_az, axis_gx, axis_gy, axis_gz);
|
||||
#ifdef USE_MPU6050_DMP
|
||||
WSContentSend_PD(HTTP_SNS_YPR, axis_yaw, axis_pitch, axis_roll);
|
||||
|
|
|
@ -80,16 +80,16 @@ extern "C" {
|
|||
#define D_TX20_WIND_ANGLE "∠"
|
||||
#define D_TX20_WIND_DEGREE "°"
|
||||
const char HTTP_SNS_TX2X[] PROGMEM =
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED "{m}%s %s{e}"
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED "{m}%1_f %s{e}"
|
||||
#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED " " D_TX20_WIND_AVG "{m}%s %s{e}"
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED_MIN "{m}%s %s{e}"
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED_MAX "{m}%s %s{e}"
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED " " D_TX20_WIND_AVG "{m}%1_f %s{e}"
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED_MIN "{m}%1_f %s{e}"
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED_MAX "{m}%1_f %s{e}"
|
||||
#endif // USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_DIRECTION "{m}%s %s" D_TX20_WIND_DEGREE "{e}"
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_DIRECTION "{m}%s %1_f" D_TX20_WIND_DEGREE "{e}"
|
||||
#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_DIRECTION " " D_TX20_WIND_AVG "{m}%s %s" D_TX20_WIND_DEGREE "{e}"
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_DIRECTION " " D_TX20_WIND_ANGLE "{m}%s" D_TX20_WIND_DEGREE " (%s,%s)" D_TX20_WIND_DEGREE;
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_DIRECTION " " D_TX20_WIND_AVG "{m}%s %1_f" D_TX20_WIND_DEGREE "{e}"
|
||||
"{s}" D_TX2x_NAME " " D_TX20_WIND_DIRECTION " " D_TX20_WIND_ANGLE "{m}%1_f" D_TX20_WIND_DEGREE " (%1_f,%1_f)" D_TX20_WIND_DEGREE;
|
||||
#endif // USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
;
|
||||
#endif // USE_WEBSERVER
|
||||
|
@ -412,19 +412,13 @@ void Tx2xRead(void)
|
|||
}
|
||||
|
||||
#ifdef DEBUG_TASMOTA_SENSOR
|
||||
char diravg[FLOATSZ];
|
||||
dtostrfd(tx2x_wind_direction_avg, 1, diravg);
|
||||
char cosx[FLOATSZ];
|
||||
dtostrfd(tx2x_wind_direction_avg_x, 1, cosx);
|
||||
char siny[FLOATSZ];
|
||||
dtostrfd(tx2x_wind_direction_avg_y, 1, siny);
|
||||
DEBUG_SENSOR_LOG(PSTR(D_TX2x_NAME ": dir stat - counter=%ld, actint=%ld, avgint=%ld, avg=%s (cosx=%s, siny=%s), min %d, max %d"),
|
||||
DEBUG_SENSOR_LOG(PSTR(D_TX2x_NAME ": dir stat - counter=%ld, actint=%ld, avgint=%ld, avg=%1_f (cosx=%1_f, siny=%1_f), min %d, max %d"),
|
||||
(TasmotaGlobal.uptime-tx2x_last_uptime),
|
||||
tx2x_wind_direction,
|
||||
tx2x_wind_direction_avg_int,
|
||||
diravg,
|
||||
cosx,
|
||||
siny,
|
||||
&tx2x_wind_direction_avg,
|
||||
&tx2x_wind_direction_avg_x,
|
||||
&tx2x_wind_direction_avg_y,
|
||||
tx2x_wind_direction_min,
|
||||
tx2x_wind_direction_max
|
||||
);
|
||||
|
@ -484,86 +478,77 @@ void Tx2xShow(bool json)
|
|||
{
|
||||
if (!Tx2xAvailable()) { return; }
|
||||
|
||||
char wind_speed_string[FLOATSZ];
|
||||
dtostrfd(ConvertSpeed(tx2x_wind_speed)/10, 1, wind_speed_string);
|
||||
char wind_direction_string[FLOATSZ];
|
||||
dtostrfd(tx2x_wind_direction*22.5, 1, wind_direction_string);
|
||||
float wind_speed_float = ConvertSpeed(tx2x_wind_speed) / 10;
|
||||
float wind_direction_float = tx2x_wind_direction * 22.5;
|
||||
char wind_direction_cardinal_string[TX2X_DIRECTIONS_MAXSIZE+1];
|
||||
GetTextIndexed(wind_direction_cardinal_string, sizeof(wind_direction_cardinal_string), tx2x_wind_direction, kTx2xDirections);
|
||||
#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
char wind_speed_min_string[FLOATSZ];
|
||||
dtostrfd(ConvertSpeed(tx2x_wind_speed_min)/10, 1, wind_speed_min_string);
|
||||
char wind_speed_max_string[FLOATSZ];
|
||||
dtostrfd(ConvertSpeed(tx2x_wind_speed_max)/10, 1, wind_speed_max_string);
|
||||
char wind_speed_avg_string[FLOATSZ];
|
||||
dtostrfd(ConvertSpeed(tx2x_wind_speed_avg)/10, 1, wind_speed_avg_string);
|
||||
char wind_direction_avg_string[FLOATSZ];
|
||||
dtostrfd(tx2x_wind_direction_avg, 1, wind_direction_avg_string);
|
||||
float wind_speed_min_float = ConvertSpeed(tx2x_wind_speed_min) / 10;
|
||||
float wind_speed_max_float = ConvertSpeed(tx2x_wind_speed_max) / 10;
|
||||
float wind_speed_avg_float = ConvertSpeed(tx2x_wind_speed_avg) / 10;
|
||||
float wind_direction_avg_float = tx2x_wind_direction_avg;
|
||||
char wind_direction_avg_cardinal_string[4];
|
||||
GetTextIndexed(wind_direction_avg_cardinal_string, sizeof(wind_direction_avg_cardinal_string), int((tx2x_wind_direction_avg/22.5f)+0.5f) % 16, kTx2xDirections);
|
||||
char wind_direction_range_string[FLOATSZ];
|
||||
dtostrfd(Tx2xNormalize(tx2x_wind_direction_max-tx2x_wind_direction_min)*22.5, 1, wind_direction_range_string);
|
||||
char wind_direction_min_string[FLOATSZ];
|
||||
dtostrfd(Tx2xNormalize(tx2x_wind_direction_min)*22.5, 1, wind_direction_min_string);
|
||||
char wind_direction_max_string[FLOATSZ];
|
||||
dtostrfd(Tx2xNormalize(tx2x_wind_direction_max)*22.5, 1, wind_direction_max_string);
|
||||
float wind_direction_range_float = (tx2x_wind_direction_max-tx2x_wind_direction_min) * 22.5;
|
||||
float wind_direction_min_float = Tx2xNormalize(tx2x_wind_direction_min) * 22.5;
|
||||
float wind_direction_max_float = tx2x_wind_direction_max * 22.5;
|
||||
#endif // USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
|
||||
if (json) {
|
||||
#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
#ifdef USE_TX2x_LEGACY_JSON
|
||||
ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":%s,\"SpeedAvg\":%s,\"SpeedMax\":%s,\"Direction\":\"%s\",\"Degree\":%s}"),
|
||||
wind_speed_string,
|
||||
wind_speed_avg_string,
|
||||
wind_speed_max_string,
|
||||
ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":%1_f,\"SpeedAvg\":%1_f,\"SpeedMax\":%1_f,\"Direction\":\"%s\",\"Degree\":%1_f}"),
|
||||
&wind_speed_float,
|
||||
&wind_speed_avg_float,
|
||||
&wind_speed_max_float,
|
||||
wind_direction_cardinal_string,
|
||||
wind_direction_string
|
||||
&wind_direction_float
|
||||
);
|
||||
#else // USE_TX2x_LEGACY_JSON
|
||||
ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":{\"Act\":%s,\"Avg\":%s,\"Min\":%s,\"Max\":%s},\"Dir\":{\"Card\":\"%s\",\"Deg\":%s,\"Avg\":%s,\"AvgCard\":\"%s\",\"Min\":%s,\"Max\":%s,\"Range\":%s}}"),
|
||||
wind_speed_string,
|
||||
wind_speed_avg_string,
|
||||
wind_speed_min_string,
|
||||
wind_speed_max_string,
|
||||
ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":{\"Act\":%1_f,\"Avg\":%1_f,\"Min\":%1_f,\"Max\":%1_f},\"Dir\":{\"Card\":\"%s\",\"Deg\":%1_f,\"Avg\":%1_f,\"AvgCard\":\"%s\",\"Min\":%1_f,\"Max\":%1_f,\"Range\":%1_f}}"),
|
||||
&wind_speed_float,
|
||||
&wind_speed_avg_float,
|
||||
&wind_speed_min_float,
|
||||
&wind_speed_max_float,
|
||||
wind_direction_cardinal_string,
|
||||
wind_direction_string,
|
||||
wind_direction_avg_string,
|
||||
&wind_direction_float,
|
||||
&wind_direction_avg_float,
|
||||
wind_direction_avg_cardinal_string,
|
||||
wind_direction_min_string,
|
||||
wind_direction_max_string,
|
||||
wind_direction_range_string
|
||||
&wind_direction_min_float,
|
||||
&wind_direction_max_float,
|
||||
&wind_direction_range_float
|
||||
);
|
||||
#endif // USE_TX2x_LEGACY_JSON
|
||||
#else // USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
#ifdef USE_TX2x_LEGACY_JSON
|
||||
ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":%s,\"Direction\":\"%s\",\"Degree\":%s}"),
|
||||
wind_speed_string, wind_direction_cardinal_string, wind_direction_string);
|
||||
ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":%1_f,\"Direction\":\"%s\",\"Degree\":%1_f}"),
|
||||
&wind_speed_float, wind_direction_cardinal_string, &wind_direction_float);
|
||||
#else // USE_TX2x_LEGACY_JSON
|
||||
ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":{\"Act\":%s},\"Dir\":{\"Card\":\"%s\",\"Deg\":%s}}"),
|
||||
wind_speed_string, wind_direction_cardinal_string, wind_direction_string);
|
||||
ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":{\"Act\":%1_f},\"Dir\":{\"Card\":\"%s\",\"Deg\":%1_f}}"),
|
||||
&wind_speed_float, wind_direction_cardinal_string, &wind_direction_float);
|
||||
#endif // USE_TX2x_LEGACY_JSON
|
||||
#endif // USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TX2X,
|
||||
wind_speed_string,
|
||||
&wind_speed_float,
|
||||
SpeedUnit().c_str(),
|
||||
#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
wind_speed_avg_string,
|
||||
&wind_speed_avg_float,
|
||||
SpeedUnit().c_str(),
|
||||
wind_speed_min_string,
|
||||
&wind_speed_min_float,
|
||||
SpeedUnit().c_str(),
|
||||
wind_speed_max_string,
|
||||
&wind_speed_max_float,
|
||||
SpeedUnit().c_str(),
|
||||
#endif // USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
wind_direction_cardinal_string,
|
||||
wind_direction_string
|
||||
&wind_direction_float
|
||||
#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
,wind_direction_avg_cardinal_string,
|
||||
wind_direction_avg_string,
|
||||
wind_direction_range_string,
|
||||
wind_direction_min_string,
|
||||
wind_direction_max_string
|
||||
&wind_direction_avg_float,
|
||||
&wind_direction_range_float,
|
||||
&wind_direction_min_float,
|
||||
&wind_direction_max_float
|
||||
#endif // USE_TX2X_WIND_SENSOR_NOSTATISTICS
|
||||
);
|
||||
#endif // USE_WEBSERVER
|
||||
|
|
|
@ -272,22 +272,21 @@ void RfSnsTheoV2Show(bool json)
|
|||
sensor, GetDT(rfsns_theo_v2_t1[i].time).c_str(), voltage);
|
||||
}
|
||||
} else {
|
||||
char temperature[33];
|
||||
dtostrfd(ConvertTemp((float)rfsns_theo_v2_t1[i].temp / 100), Settings.flag2.temperature_resolution, temperature);
|
||||
float temp = ConvertTemp((float)rfsns_theo_v2_t1[i].temp / 100)
|
||||
|
||||
if (json) {
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_ILLUMINANCE "\":%d,\"" D_JSON_VOLTAGE "\":%s}"),
|
||||
sensor, temperature, rfsns_theo_v2_t1[i].lux, voltage);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%*_f,\"" D_JSON_ILLUMINANCE "\":%d,\"" D_JSON_VOLTAGE "\":%s}"),
|
||||
sensor, Settings.flag2.temperature_resolution, &temp, rfsns_theo_v2_t1[i].lux, voltage);
|
||||
#ifdef USE_DOMOTICZ
|
||||
if ((0 == TasmotaGlobal.tele_period) && !sensor_once) {
|
||||
DomoticzSensor(DZ_TEMP, temperature);
|
||||
DomoticzFloatSensor(DZ_TEMP, temp);
|
||||
DomoticzSensor(DZ_ILLUMINANCE, rfsns_theo_v2_t1[i].lux);
|
||||
sensor_once = true;
|
||||
}
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, sensor, temperature, TempUnit());
|
||||
WSContentSend_Temp(sensor, temp);
|
||||
WSContentSend_PD(HTTP_SNS_ILLUMINANCE, sensor, rfsns_theo_v2_t1[i].lux);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
|
|
|
@ -139,20 +139,18 @@ void MAX31855_GetResult(void) {
|
|||
}
|
||||
|
||||
void MAX31855_Show(bool Json) {
|
||||
char probetemp[33];
|
||||
char referencetemp[33];
|
||||
dtostrfd(MAX31855_Result.ProbeTemperature, Settings.flag2.temperature_resolution, probetemp);
|
||||
dtostrfd(MAX31855_Result.ReferenceTemperature, Settings.flag2.temperature_resolution, referencetemp);
|
||||
|
||||
char sensor_name[10];
|
||||
GetTextIndexed(sensor_name, sizeof(sensor_name), Settings.flag4.max6675, kMax31855Types);
|
||||
|
||||
if (Json) {
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_PROBETEMPERATURE "\":%s,\"" D_JSON_REFERENCETEMPERATURE "\":%s,\"" D_JSON_ERROR "\":%d}"), \
|
||||
sensor_name, probetemp, referencetemp, MAX31855_Result.ErrorCode);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_PROBETEMPERATURE "\":%*_f,\"" D_JSON_REFERENCETEMPERATURE "\":%*_f,\"" D_JSON_ERROR "\":%d}"), \
|
||||
sensor_name,
|
||||
Settings.flag2.temperature_resolution, &MAX31855_Result.ProbeTemperature,
|
||||
Settings.flag2.temperature_resolution, &MAX31855_Result.ReferenceTemperature,
|
||||
MAX31855_Result.ErrorCode);
|
||||
#ifdef USE_DOMOTICZ
|
||||
if (0 == TasmotaGlobal.tele_period) {
|
||||
DomoticzSensor(DZ_TEMP, probetemp);
|
||||
DomoticzFloatSensor(DZ_TEMP, MAX31855_Result.ProbeTemperature);
|
||||
}
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_KNX
|
||||
|
@ -162,7 +160,7 @@ void MAX31855_Show(bool Json) {
|
|||
#endif // USE_KNX
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, sensor_name, probetemp, TempUnit());
|
||||
WSContentSend_Temp(sensor_name, MAX31855_Result.ProbeTemperature);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,18 +88,15 @@ void MAX31865_Show(bool Json) {
|
|||
uint8_t report_once = 0;
|
||||
for (uint32_t i = 0; i < MAX_MAX31865S; i++) {
|
||||
if (max31865_pins_used & (1 << i)) {
|
||||
char temperature[33];
|
||||
char resistance[33];
|
||||
|
||||
dtostrfd(MAX31865_Result[i].PtdResistance, Settings.flag2.temperature_resolution, resistance);
|
||||
dtostrfd(MAX31865_Result[i].PtdTemp, Settings.flag2.temperature_resolution, temperature);
|
||||
|
||||
if (Json) {
|
||||
ResponseAppend_P(PSTR(",\"MAX31865%c%d\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_RESISTANCE "\":%s,\"" D_JSON_ERROR "\":%d}"), \
|
||||
IndexSeparator(), i, temperature, resistance, MAX31865_Result[i].ErrorCode);
|
||||
ResponseAppend_P(PSTR(",\"MAX31865%c%d\":{\"" D_JSON_TEMPERATURE "\":%*_f,\"" D_JSON_RESISTANCE "\":%*_f,\"" D_JSON_ERROR "\":%d}"), \
|
||||
IndexSeparator(), i,
|
||||
Settings.flag2.temperature_resolution, &MAX31865_Result[i].PtdTemp,
|
||||
Settings.flag2.temperature_resolution, &MAX31865_Result[i].PtdResistance,
|
||||
MAX31865_Result[i].ErrorCode);
|
||||
if ((0 == TasmotaGlobal.tele_period) && (!report_once)) {
|
||||
#ifdef USE_DOMOTICZ
|
||||
DomoticzSensor(DZ_TEMP, temperature);
|
||||
DomoticzFloatSensor(DZ_TEMP, MAX31865_Result[i].PtdTemp);
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_KNX
|
||||
KnxSensor(KNX_TEMPERATURE, MAX31865_Result[i].PtdTemp);
|
||||
|
@ -110,7 +107,7 @@ void MAX31865_Show(bool Json) {
|
|||
} else {
|
||||
char sensorname[33];
|
||||
sprintf(sensorname, "MAX31865%c%d", IndexSeparator(), i);
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, sensorname, temperature, TempUnit());
|
||||
WSContentSend_Temp(sensorname, MAX31865_Result[i].PtdTemp);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
|
|
@ -417,10 +417,8 @@ void ChirpShow(bool json)
|
|||
{
|
||||
for (uint32_t i = 0; i < chirp_found_sensors; i++) {
|
||||
if (chirp_sensor[i].version) {
|
||||
// convert double values to string
|
||||
char str_temperature[33];
|
||||
double t_temperature = ((double) chirp_sensor[i].temperature )/10.0;
|
||||
dtostrfd(t_temperature, Settings.flag2.temperature_resolution, str_temperature);
|
||||
float t_temperature = ConvertTemp(((float)chirp_sensor[i].temperature )/10.0);
|
||||
|
||||
char str_light[33];
|
||||
dtostrfd(chirp_sensor[i].light, 0, str_light);
|
||||
char str_version[7];
|
||||
|
@ -435,7 +433,7 @@ void ChirpShow(bool json)
|
|||
if(!chirp_sensor[i].explicitSleep) {
|
||||
ResponseAppend_P(PSTR(",\"%s%u\":{\"" D_JSON_MOISTURE "\":%d"), chirp_name, i, chirp_sensor[i].moisture);
|
||||
if(chirp_sensor[i].temperature!=-1){ // this is the error code -> no temperature
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s"),str_temperature);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%*_f"), Settings.flag2.temperature_resolution, &t_temperature);
|
||||
}
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_DARKNESS "\":%s}"),str_light);
|
||||
}
|
||||
|
@ -458,7 +456,7 @@ void ChirpShow(bool json)
|
|||
WSContentSend_PD(HTTP_SNS_MOISTURE, "", chirp_sensor[i].moisture);
|
||||
WSContentSend_PD(HTTP_SNS_DARKNESS, str_light);
|
||||
if (chirp_sensor[i].temperature!=-1) { // this is the error code -> no temperature
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, "", str_temperature, TempUnit());
|
||||
WSContentSend_Temp("", t_temperature);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -176,18 +176,16 @@ void DS1624EverySecond(void)
|
|||
|
||||
void DS1624Show(bool json)
|
||||
{
|
||||
char temperature[33];
|
||||
bool once = true;
|
||||
|
||||
for (uint32_t i = 0; i < DS1624_MAX_SENSORS; i++) {
|
||||
if (!ds1624_sns[i].valid) { continue; }
|
||||
|
||||
dtostrfd(ds1624_sns[i].value, Settings.flag2.temperature_resolution, temperature);
|
||||
if (json) {
|
||||
ResponseAppend_P(JSON_SNS_TEMP, ds1624_sns[i].name, temperature);
|
||||
ResponseAppend_P(JSON_SNS_F_TEMP, ds1624_sns[i].name, Settings.flag2.temperature_resolution, &ds1624_sns[i].value);
|
||||
if ((0 == TasmotaGlobal.tele_period) && once) {
|
||||
#ifdef USE_DOMOTICZ
|
||||
DomoticzSensor(DZ_TEMP, temperature);
|
||||
DomoticzFloatSensor(DZ_TEMP, ds1624_sns[i].value);
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_KNX
|
||||
KnxSensor(KNX_TEMPERATURE, ds1624_sns[i].value);
|
||||
|
@ -196,7 +194,7 @@ void DS1624Show(bool json)
|
|||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, ds1624_sns[i].name, temperature, TempUnit());
|
||||
WSContentSend_Temp(ds1624_sns[i].name, ds1624_sns[i].value);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1738,9 +1738,8 @@ void MINRFShow(bool json)
|
|||
||(hass_mode==2)
|
||||
#endif //USE_HOME_ASSISTANT
|
||||
) {
|
||||
char temperature[FLOATSZ];
|
||||
dtostrfd(MIBLEsensors[i].temp, Settings.flag2.temperature_resolution, temperature);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s"), temperature);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%*_f"),
|
||||
Settings.flag2.temperature_resolution, &MIBLEsensors[i].temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1897,9 +1896,7 @@ void MINRFShow(bool json)
|
|||
if (MIBLEsensors[i].type==YEERC) continue;
|
||||
if (MIBLEsensors[i].type==FLORA){
|
||||
if(!isnan(MIBLEsensors[i].temp)){
|
||||
char temperature[FLOATSZ];
|
||||
dtostrfd(MIBLEsensors[i].temp, Settings.flag2.temperature_resolution, temperature);
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, kMINRFDeviceType[MIBLEsensors[i].type-1], temperature, TempUnit());
|
||||
WSContentSend_Temp(kMINRFDeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].temp);
|
||||
}
|
||||
if(MIBLEsensors[i].lux!=0xffffffff){ // this is the error code -> no valid value
|
||||
WSContentSend_PD(HTTP_SNS_ILLUMINANCE, kMINRFDeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].lux);
|
||||
|
|
|
@ -2052,9 +2052,8 @@ void MI32Show(bool json)
|
|||
||(hass_mode!=-1)
|
||||
#endif //USE_HOME_ASSISTANT
|
||||
) {
|
||||
char temperature[FLOATSZ];
|
||||
dtostrfd(MIBLEsensors[i].temp, Settings.flag2.temperature_resolution, temperature);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s"), temperature);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%*_f"),
|
||||
Settings.flag2.temperature_resolution, &MIBLEsensors[i].temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2211,9 +2210,7 @@ void MI32Show(bool json)
|
|||
WSContentSend_PD(HTTP_RSSI, kMI32DeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].RSSI);
|
||||
if (MIBLEsensors[i].type==FLORA) {
|
||||
if (!isnan(MIBLEsensors[i].temp)) {
|
||||
char temperature[FLOATSZ];
|
||||
dtostrfd(MIBLEsensors[i].temp, Settings.flag2.temperature_resolution, temperature);
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, kMI32DeviceType[MIBLEsensors[i].type-1], temperature, TempUnit());
|
||||
WSContentSend_Temp(kMI32DeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].temp);
|
||||
}
|
||||
if (MIBLEsensors[i].moisture!=0xff) {
|
||||
WSContentSend_PD(HTTP_SNS_MOISTURE, kMI32DeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].moisture);
|
||||
|
|
|
@ -79,6 +79,7 @@ void MI32notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pD
|
|||
struct {
|
||||
uint16_t perPage = 4;
|
||||
uint8_t mqttCurrentSlot = 0;
|
||||
uint8_t mqttCurrentSingleSlot = 0;
|
||||
uint32_t period; // set manually in addition to TELE-period, is set to TELE-period after start
|
||||
int secondsCounter = 0; // counts up in MI32EverySecond to period
|
||||
int secondsCounter2 = 0; // counts up in MI32EverySecond to period
|
||||
|
@ -116,6 +117,7 @@ struct {
|
|||
uint32_t showRSSI:1;
|
||||
uint32_t ignoreBogusBattery:1;
|
||||
uint32_t minimalSummary:1; // DEPRECATED!!
|
||||
uint32_t onlyAliased:1; // only include sensors that are aliased
|
||||
} option;
|
||||
} MI32;
|
||||
|
||||
|
@ -255,6 +257,8 @@ struct mi_sensor_t{
|
|||
uint8_t type; //MI_Flora = 1; MI_MI-HT_V1=2; MI_LYWSD02=3; MI_LYWSD03=4; MI_CGG1=5; MI_CGD1=6
|
||||
uint8_t needkey; // tells http to display needkey message with link
|
||||
uint8_t lastCnt; //device generated counter of the packet
|
||||
uint8_t nextDiscoveryData; // used to lkimit discovery to one MQTT per sec
|
||||
|
||||
uint8_t shallSendMQTT;
|
||||
uint8_t MAC[6];
|
||||
union {
|
||||
|
@ -918,6 +922,12 @@ int MI32advertismentCallback(BLE_ESP32::ble_advertisment_t *pStruct)
|
|||
int RSSI = pStruct->RSSI;
|
||||
const uint8_t *addr = pStruct->addr;
|
||||
if(MI32isInBlockList(addr) == true) return 0;
|
||||
if (MI32.option.onlyAliased){
|
||||
const char *alias = BLE_ESP32::getAlias(addr);
|
||||
if (!alias || !(*alias)){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int svcdataCount = advertisedDevice->getServiceDataCount();
|
||||
|
||||
|
@ -1880,6 +1890,9 @@ void MI32EverySecond(bool restart){
|
|||
|
||||
MI32ShowSomeSensors();
|
||||
|
||||
MI32DiscoveryOneMISensor();
|
||||
MI32ShowOneMISensor();
|
||||
|
||||
// read a battery if
|
||||
// MI32.batteryreader.slot < filled and !MI32.batteryreader.active
|
||||
readOneBat();
|
||||
|
@ -1906,10 +1919,12 @@ void MI32EverySecond(bool restart){
|
|||
AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Kick off tele sending"));
|
||||
MI32.mqttCurrentSlot = 0;
|
||||
MI32.secondsCounter2 = 0;
|
||||
MI32.mqttCurrentSingleSlot = 0;
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Hit tele time, restarted but not finished last - lost from slot %d")+MI32.mqttCurrentSlot);
|
||||
MI32.mqttCurrentSlot = 0;
|
||||
MI32.secondsCounter2 = 0;
|
||||
MI32.mqttCurrentSingleSlot = 0;
|
||||
}
|
||||
}
|
||||
MI32.secondsCounter2++;
|
||||
|
@ -2112,6 +2127,13 @@ void CmndMi32Option(void){
|
|||
case 4:{
|
||||
MI32.option.ignoreBogusBattery = onOff;
|
||||
} break;
|
||||
case 5:{
|
||||
MI32.option.onlyAliased = onOff;
|
||||
if (MI32.option.onlyAliased){
|
||||
// discard all sensors for a restart
|
||||
MIBLEsensors.clear();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
@ -2302,15 +2324,18 @@ void MI32TimeoutSensors(){
|
|||
|
||||
|
||||
// this assumes that we're adding to a ResponseTime_P
|
||||
void MI32GetOneSensorJson(int slot){
|
||||
void MI32GetOneSensorJson(int slot, int hidename){
|
||||
mi_sensor_t *p;
|
||||
p = &MIBLEsensors[slot];
|
||||
|
||||
ResponseAppend_P(PSTR(",\"%s-%02x%02x%02x\":{"),
|
||||
kMI32DeviceType[p->type-1],
|
||||
p->MAC[3], p->MAC[4], p->MAC[5]);
|
||||
// remove hyphen - make it difficult to configure HASS
|
||||
if (!hidename) {
|
||||
ResponseAppend_P(PSTR("\"%s%02x%02x%02x\":{"),
|
||||
kMI32DeviceType[p->type-1],
|
||||
p->MAC[3], p->MAC[4], p->MAC[5]);
|
||||
}
|
||||
|
||||
ResponseAppend_P(PSTR("\"MAC\":\"%02x%02x%02x%02x%02x%02x\""),
|
||||
ResponseAppend_P(PSTR("\"mac\":\"%02x%02x%02x%02x%02x%02x\""),
|
||||
p->MAC[0], p->MAC[1], p->MAC[2],
|
||||
p->MAC[3], p->MAC[4], p->MAC[5]);
|
||||
|
||||
|
@ -2336,9 +2361,8 @@ void MI32GetOneSensorJson(int slot){
|
|||
||(hass_mode!=-1)
|
||||
#endif //USE_HOME_ASSISTANT
|
||||
) {
|
||||
char temperature[FLOATSZ];
|
||||
dtostrfd(p->temp, Settings.flag2.temperature_resolution, temperature);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s"), temperature);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%*_f"),
|
||||
Settings.flag2.temperature_resolution, &p->temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2449,7 +2473,9 @@ void MI32GetOneSensorJson(int slot){
|
|||
}
|
||||
if (MI32.option.showRSSI) ResponseAppend_P(PSTR(",\"RSSI\":%d"), p->RSSI);
|
||||
|
||||
ResponseAppend_P(PSTR("}"));
|
||||
if (!hidename) {
|
||||
ResponseAppend_P(PSTR("}"));
|
||||
}
|
||||
p->eventType.raw = 0;
|
||||
p->shallSendMQTT = 0;
|
||||
|
||||
|
@ -2486,7 +2512,8 @@ void MI32ShowSomeSensors(){
|
|||
ResponseTime_P(PSTR(""));
|
||||
int cnt = 0;
|
||||
for (; (MI32.mqttCurrentSlot < numsensors) && (cnt < 4); MI32.mqttCurrentSlot++, cnt++) {
|
||||
MI32GetOneSensorJson(MI32.mqttCurrentSlot);
|
||||
ResponseAppend_P(PSTR(","));
|
||||
MI32GetOneSensorJson(MI32.mqttCurrentSlot, 0);
|
||||
int mlen = strlen(TasmotaGlobal.mqtt_data);
|
||||
|
||||
// if we ran out of room, leave here.
|
||||
|
@ -2511,6 +2538,185 @@ void MI32ShowSomeSensors(){
|
|||
#endif //USE_HOME_ASSISTANT
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// starts a completely fresh MQTT message.
|
||||
// sends ONE sensor on a dedicated topic NOT related to this TAS
|
||||
// triggered by setting MI32.mqttCurrentSingleSlot = 0
|
||||
void MI32ShowOneMISensor(){
|
||||
// don't detect half-added ones here
|
||||
int numsensors = MIBLEsensors.size();
|
||||
if (MI32.mqttCurrentSingleSlot >= numsensors){
|
||||
// if we got to the end of the sensors, then don't send more
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_HOME_ASSISTANT
|
||||
if(Settings.flag.hass_discovery){
|
||||
|
||||
ResponseTime_P(PSTR(","));
|
||||
MI32GetOneSensorJson(MI32.mqttCurrentSingleSlot, 1);
|
||||
mi_sensor_t *p;
|
||||
p = &MIBLEsensors[MI32.mqttCurrentSingleSlot];
|
||||
|
||||
ResponseAppend_P(PSTR("}"));
|
||||
|
||||
char idstr[32];
|
||||
const char *alias = BLE_ESP32::getAlias(p->MAC);
|
||||
const char *id = idstr;
|
||||
if (alias && *alias){
|
||||
id = alias;
|
||||
} else {
|
||||
sprintf(idstr, PSTR("%s%02x%02x%02x"),
|
||||
kMI32DeviceType[p->type-1],
|
||||
p->MAC[3], p->MAC[4], p->MAC[5]);
|
||||
}
|
||||
char SensorTopic[60];
|
||||
sprintf(SensorTopic, "tele/tasmota_ble/%s",
|
||||
id);
|
||||
|
||||
MqttPublish(SensorTopic);
|
||||
//AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: %s: show some %d %s"),D_CMND_MI32, MI32.mqttCurrentSlot, TasmotaGlobal.mqtt_data);
|
||||
}
|
||||
#endif //USE_HOME_ASSISTANT
|
||||
MI32.mqttCurrentSingleSlot++;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// starts a completely fresh MQTT message.
|
||||
// sends ONE sensor's worth of HA discovery msg
|
||||
const char MI_HA_DISCOVERY_TEMPLATE[] PROGMEM =
|
||||
"{\"availability\":[],\"device\":"
|
||||
"{\"identifiers\":[\"BLE%s\"],"
|
||||
"\"name\":\"%s\","
|
||||
"\"manufacturer\":\"tas\","
|
||||
"\"model\":\"%s\","
|
||||
"\"via_device\":\"%s\""
|
||||
"},"
|
||||
"\"dev_cla\":\"%s\","
|
||||
"\"expire_after\":600,"
|
||||
"\"json_attr_t\":\"%s\","
|
||||
"\"name\":\"%s_%s\","
|
||||
"\"state_topic\":\"%s\","
|
||||
"\"uniq_id\":\"%s_%s\","
|
||||
"\"unit_of_meas\":\"%s\","
|
||||
"\"val_tpl\":\"{{ value_json.%s }}\"}";
|
||||
|
||||
void MI32DiscoveryOneMISensor(){
|
||||
// don't detect half-added ones here
|
||||
int numsensors = MIBLEsensors.size();
|
||||
if (MI32.mqttCurrentSingleSlot >= numsensors){
|
||||
// if we got to the end of the sensors, then don't send more
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_HOME_ASSISTANT
|
||||
if(Settings.flag.hass_discovery){
|
||||
mi_sensor_t *p;
|
||||
p = &MIBLEsensors[MI32.mqttCurrentSingleSlot];
|
||||
|
||||
|
||||
// careful - a missing comma causes a crash!!!!
|
||||
// because of the way we loop?
|
||||
const char *classes[] = {
|
||||
"temperature",
|
||||
"Temperature",
|
||||
"°C",
|
||||
"humidity",
|
||||
"Humidity",
|
||||
"%",
|
||||
"temperature",
|
||||
"DewPoint",
|
||||
"°C",
|
||||
"battery",
|
||||
"Battery",
|
||||
"%",
|
||||
"signal_strength",
|
||||
"RSSI",
|
||||
"dB"
|
||||
};
|
||||
|
||||
int datacount = (sizeof(classes)/sizeof(*classes))/3;
|
||||
|
||||
if (p->nextDiscoveryData >= datacount){
|
||||
p->nextDiscoveryData = 0;
|
||||
}
|
||||
|
||||
//int i = p->nextDiscoveryData*3;
|
||||
for (int i = 0; i < datacount*3; i += 3){
|
||||
if (!classes[i] || !classes[i+1] || !classes[i+2]){
|
||||
return;
|
||||
}
|
||||
|
||||
char idstr[32];
|
||||
const char *alias = BLE_ESP32::getAlias(p->MAC);
|
||||
const char *id = idstr;
|
||||
if (alias && *alias){
|
||||
id = alias;
|
||||
} else {
|
||||
sprintf(idstr, PSTR("%s%02x%02x%02x"),
|
||||
kMI32DeviceType[p->type-1],
|
||||
p->MAC[3], p->MAC[4], p->MAC[5]);
|
||||
}
|
||||
|
||||
char SensorTopic[60];
|
||||
sprintf(SensorTopic, "tele/tasmota_ble/%s",
|
||||
id);
|
||||
|
||||
|
||||
ResponseClear();
|
||||
|
||||
/*
|
||||
{"availability":[],"device":{"identifiers":["TasmotaBLEa4c1387fc1e1"],"manufacturer":"simon","model":"someBLEsensor","name":"TASBLEa4c1387fc1e1","sw_version":"0.0.0"},"dev_cla":"temperature","json_attr_t":"tele/tasmota_esp32/SENSOR","name":"TASLYWSD037fc1e1Temp","state_topic":"tele/tasmota_esp32/SENSOR","uniq_id":"Tasmotaa4c1387fc1e1temp","unit_of_meas":"°C","val_tpl":"{{ value_json.LYWSD037fc1e1.Temperature }}"}
|
||||
{"availability":[],"device":{"identifiers":["TasmotaBLEa4c1387fc1e1"],
|
||||
"name":"TASBLEa4c1387fc1e1"},"dev_cla":"temperature",
|
||||
"json_attr_t":"tele/tasmota_esp32/SENSOR",
|
||||
"name":"TASLYWSD037fc1e1Temp","state_topic": "tele/tasmota_esp32/SENSOR",
|
||||
"uniq_id":"Tasmotaa4c1387fc1e1temp","unit_of_meas":"°C",
|
||||
"val_tpl":"{{ value_json.LYWSD037fc1e1.Temperature }}"}
|
||||
*/
|
||||
|
||||
ResponseAppend_P(MI_HA_DISCOVERY_TEMPLATE,
|
||||
//"{\"identifiers\":[\"BLE%s\"],"
|
||||
id,
|
||||
//"\"name\":\"%s\"},"
|
||||
id,
|
||||
//\"model\":\"%s\",
|
||||
kMI32DeviceType[p->type-1],
|
||||
//\"via_device\":\"%s\"
|
||||
NetworkHostname(),
|
||||
//"\"dev_cla\":\"%s\","
|
||||
classes[i],
|
||||
//"\"json_attr_t\":\"%s\"," - the topic the sensor publishes on
|
||||
SensorTopic,
|
||||
//"\"name\":\"%s_%s\"," - the name of this DATA
|
||||
id, classes[i+1],
|
||||
//"\"state_topic\":\"%s\"," - the topic the sensor publishes on?
|
||||
SensorTopic,
|
||||
//"\"uniq_id\":\"%s_%s\"," - unique for this data,
|
||||
id, classes[i+1],
|
||||
//"\"unit_of_meas\":\"%s\"," - the measure of this type of data
|
||||
classes[i+2],
|
||||
//"\"val_tpl\":\"{{ value_json.%s }}") // e.g. Temperature
|
||||
classes[i+1]
|
||||
//
|
||||
);
|
||||
|
||||
char DiscoveryTopic[80];
|
||||
sprintf(DiscoveryTopic, "homeassistant/sensor/%s/%s/config",
|
||||
id, classes[i+1]);
|
||||
|
||||
MqttPublish(DiscoveryTopic);
|
||||
p->nextDiscoveryData++;
|
||||
//vTaskDelay(100/ portTICK_PERIOD_MS);
|
||||
}
|
||||
} // end if hass discovery
|
||||
//AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: %s: show some %d %s"),D_CMND_MI32, MI32.mqttCurrentSlot, TasmotaGlobal.mqtt_data);
|
||||
#endif //USE_HOME_ASSISTANT
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// starts a completely fresh MQTT message.
|
||||
// sends up to 4 sensors pe5r msg
|
||||
|
@ -2535,7 +2741,8 @@ void MI32ShowTriggeredSensors(){
|
|||
if(p->shallSendMQTT==0) continue;
|
||||
|
||||
cnt++;
|
||||
MI32GetOneSensorJson(sensor);
|
||||
ResponseAppend_P(PSTR(","));
|
||||
MI32GetOneSensorJson(sensor, 0);
|
||||
int mlen = strlen(TasmotaGlobal.mqtt_data);
|
||||
|
||||
// if we ran out of room, leave here.
|
||||
|
@ -2607,9 +2814,7 @@ void MI32Show(bool json)
|
|||
switch(p->type){
|
||||
case MI_FLORA:{
|
||||
if (!isnan(p->temp)) {
|
||||
char temperature[FLOATSZ];
|
||||
dtostrfd(p->temp, Settings.flag2.temperature_resolution, temperature);
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, typeName, temperature, TempUnit());
|
||||
WSContentSend_Temp(typeName, p->temp);
|
||||
}
|
||||
if (p->moisture!=0xff) {
|
||||
WSContentSend_PD(HTTP_SNS_MOISTURE, typeName, p->moisture);
|
||||
|
|
|
@ -1812,9 +1812,8 @@ void HM10Show(bool json)
|
|||
||(hass_mode!=-1)
|
||||
#endif //USE_HOME_ASSISTANT
|
||||
) {
|
||||
char temperature[FLOATSZ];
|
||||
dtostrfd(MIBLEsensors[i].temp, Settings.flag2.temperature_resolution, temperature);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s"), temperature);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%*_f"),
|
||||
Settings.flag2.temperature_resolution, &MIBLEsensors[i].temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1967,9 +1966,7 @@ void HM10Show(bool json)
|
|||
WSContentSend_PD(HTTP_HM10_MAC, kHM10DeviceType[MIBLEsensors[i].type-1], D_MAC_ADDRESS, _MAC);
|
||||
if (MIBLEsensors[i].type==FLORA){
|
||||
if(!isnan(MIBLEsensors[i].temp)){
|
||||
char temperature[FLOATSZ];
|
||||
dtostrfd(MIBLEsensors[i].temp, Settings.flag2.temperature_resolution, temperature);
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, kHM10DeviceType[MIBLEsensors[i].type-1], temperature, TempUnit());
|
||||
WSContentSend_Temp(kHM10DeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].temp);
|
||||
}
|
||||
if(MIBLEsensors[i].lux!=0x00ffffff){ // this is the error code -> no valid value
|
||||
WSContentSend_PD(HTTP_SNS_ILLUMINANCE, kHM10DeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].lux);
|
||||
|
|
|
@ -75,9 +75,6 @@ void MCP9808EverySecond(void) {
|
|||
|
||||
void MCP9808Show(bool json) {
|
||||
for (uint32_t i = 0; i < mcp9808_cfg.count; i++) {
|
||||
char temperature[33];
|
||||
dtostrfd(mcp9808_sensors[i].temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
|
||||
char sensor_name[11];
|
||||
strlcpy(sensor_name, mcp9808_cfg.types, sizeof(sensor_name));
|
||||
if (mcp9808_cfg.count > 1) {
|
||||
|
@ -85,10 +82,10 @@ void MCP9808Show(bool json) {
|
|||
}
|
||||
|
||||
if (json) {
|
||||
ResponseAppend_P(JSON_SNS_TEMP, sensor_name, temperature);
|
||||
ResponseAppend_P(JSON_SNS_F_TEMP, sensor_name, Settings.flag2.temperature_resolution, &mcp9808_sensors[i].temperature);
|
||||
if ((0 == TasmotaGlobal.tele_period) && (0 == i)) {
|
||||
#ifdef USE_DOMOTICZ
|
||||
DomoticzSensor(DZ_TEMP, temperature);
|
||||
DomoticzFloatSensor(DZ_TEMP, mcp9808_sensors[i].temperature);
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_KNX
|
||||
KnxSensor(KNX_TEMPERATURE, mcp9808_sensors[i].temperature);
|
||||
|
@ -96,7 +93,7 @@ void MCP9808Show(bool json) {
|
|||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, sensor_name, temperature, TempUnit());
|
||||
WSContentSend_Temp(sensor_name, mcp9808_sensors[i].temperature);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,15 +107,14 @@ void HP303B_Show(bool json) {
|
|||
|
||||
float sealevel = ConvertPressureForSeaLevel(hp303b_sensor[i].pressure);
|
||||
|
||||
char str_temperature[33];
|
||||
dtostrfd(hp303b_sensor[i].temperature, Settings.flag2.temperature_resolution, str_temperature);
|
||||
char str_pressure[33];
|
||||
dtostrfd(hp303b_sensor[i].pressure, Settings.flag2.pressure_resolution, str_pressure);
|
||||
char sea_pressure[33];
|
||||
dtostrfd(sealevel, Settings.flag2.pressure_resolution, sea_pressure);
|
||||
|
||||
if (json) {
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_PRESSURE "\":%s"), sensor_name, str_temperature, str_pressure);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%*_f,\"" D_JSON_PRESSURE "\":%s"),
|
||||
sensor_name, Settings.flag2.temperature_resolution, &hp303b_sensor[i].temperature, str_pressure);
|
||||
if (Settings.altitude != 0) {
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_PRESSUREATSEALEVEL "\":%s"), sea_pressure);
|
||||
}
|
||||
|
@ -123,12 +122,12 @@ void HP303B_Show(bool json) {
|
|||
#ifdef USE_DOMOTICZ
|
||||
// Domoticz and knx only support one temp sensor
|
||||
if ((0 == TasmotaGlobal.tele_period) && (0 == i)) {
|
||||
DomoticzSensor(DZ_TEMP, hp303b_sensor[i].temperature);
|
||||
DomoticzFloatSensor(DZ_TEMP, hp303b_sensor[i].temperature);
|
||||
}
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, sensor_name, str_temperature, TempUnit());
|
||||
WSContentSend_Temp(sensor_name, hp303b_sensor[i].temperature);
|
||||
WSContentSend_PD(HTTP_SNS_PRESSURE, sensor_name, str_pressure, PressureUnit().c_str());
|
||||
if (Settings.altitude != 0) {
|
||||
WSContentSend_PD(HTTP_SNS_SEAPRESSURE, sensor_name, sea_pressure, PressureUnit().c_str());
|
||||
|
|
|
@ -85,14 +85,11 @@ int LMT01_getPulses(void) {
|
|||
}
|
||||
|
||||
void LMT01_Show(bool Json) {
|
||||
char temp[33];
|
||||
dtostrfd(lmt01_temperature, Settings.flag2.temperature_resolution, temp);
|
||||
|
||||
if (Json) {
|
||||
ResponseAppend_P(JSON_SNS_TEMP, "LMT01", temp);
|
||||
ResponseAppend_P(JSON_SNS_F_TEMP, "LMT01", Settings.flag2.temperature_resolution, &lmt01_temperature);
|
||||
#ifdef USE_DOMOTICZ
|
||||
if (0 == TasmotaGlobal.tele_period) {
|
||||
DomoticzSensor(DZ_TEMP, temp);
|
||||
DomoticzFloatSensor(DZ_TEMP, lmt01_temperature);
|
||||
}
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_KNX
|
||||
|
@ -102,7 +99,7 @@ void LMT01_Show(bool Json) {
|
|||
#endif // USE_KNX
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, "LMT01", temp, TempUnit());
|
||||
WSContentSend_Temp("LMT01", lmt01_temperature);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,15 +35,14 @@ struct EZORTD : public EZOStruct {
|
|||
|
||||
virtual void Show(bool json, const char *name)
|
||||
{
|
||||
char str[10];
|
||||
dtostrfd(ConvertTemp(temperature), Settings.flag2.temperature_resolution, str);
|
||||
float temp = ConvertTemp(temperature);
|
||||
|
||||
if (json) {
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}"), name, str);
|
||||
ResponseAppend_P(JSON_SNS_F_TEMP, name, Settings.flag2.temperature_resolution, &temp);
|
||||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
else {
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, name, str, TempUnit());
|
||||
WSContentSend_Temp(name, temp);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
|
|
@ -272,11 +272,9 @@ void seeSoilEverySecond(void) { // update sensor values and publ
|
|||
#endif // SEESAW_SOIL_PUBLISH
|
||||
|
||||
void seeSoilShow(bool json) {
|
||||
char temperature[FLOATSZ];
|
||||
char sensor_name[sizeof(SeeSoil.name) + 3];
|
||||
|
||||
for (uint32_t i = 0; i < SeeSoil.count; i++) {
|
||||
dtostrfd(SeeSoilSNS[i].temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
seeSoilName(i, sensor_name, sizeof(sensor_name));
|
||||
if (json) {
|
||||
ResponseAppend_P(PSTR(",")); // compose tele json
|
||||
|
@ -296,20 +294,20 @@ void seeSoilShow(bool json) {
|
|||
WSContentSend_PD(HTTP_SNS_ANALOG, sensor_name, 0, SeeSoilSNS[i].capacitance);
|
||||
#endif // SEESAW_SOIL_RAW
|
||||
WSContentSend_PD(HTTP_SNS_MOISTURE, sensor_name, (uint32_t) SeeSoilSNS[i].moisture);
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, sensor_name, temperature, TempUnit());
|
||||
WSContentSend_Temp(sensor_name, SeeSoilSNS[i].temperature);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
} // for each sensor connected
|
||||
}
|
||||
|
||||
void seeSoilJson(int no) { // common json
|
||||
char temperature[FLOATSZ];
|
||||
char sensor_name[sizeof(SeeSoil.name) + 3];
|
||||
|
||||
seeSoilName(no, sensor_name, sizeof(sensor_name));
|
||||
dtostrfd(SeeSoilSNS[no].temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
ResponseAppend_P(PSTR ("\"%s\":{\"" D_JSON_ID "\":\"%02X\",\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_MOISTURE "\":%u}"),
|
||||
sensor_name, SeeSoilSNS[no].address, temperature, (uint32_t) SeeSoilSNS[no].moisture);
|
||||
|
||||
ResponseAppend_P(PSTR ("\"%s\":{\"" D_JSON_ID "\":\"%02X\",\"" D_JSON_TEMPERATURE "\":%*_f,\"" D_JSON_MOISTURE "\":%u}"),
|
||||
sensor_name, SeeSoilSNS[no].address,
|
||||
Settings.flag2.temperature_resolution, &SeeSoilSNS[no].temperature,
|
||||
(uint32_t) SeeSoilSNS[no].moisture);
|
||||
}
|
||||
|
||||
void seeSoilName(int no, char *name, int len) // generates a sensor name
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
## EmberZNet NCP UART EZSP firmware signed for Sonoff ZBBridge
|
||||
|
||||
- `ncp-uart-sw_6.7.6_115200.ota` - recommended stable version for EZSP v6, EZSP v7, and EZSP v8 compatible hosts.
|
||||
- `ncp-uart-sw-6.7.8_115200.ota` - latest version for EZSP v6, EZSP v7, and EZSP v8 compatible hosts.
|
||||
- `ncp-uart-sw_6.5.5_115200.ota` - legacy version for EZSP v4, EZSP v5, EZSP v6, or EZSP v7 compatible hosts.
|
||||
- `ncp-uart-sw_6.7.6_115200.ota` - original stable version for EZSP v8 compatible hosts, contains a bug that can cause battery of IKEA and Philips remotes to drain
|
||||
- `ncp-uart-sw-6.7.8_115200.ota` - NEW: recommended stable version for EZSP v8 compatible hosts.
|
||||
|
||||
## Archived
|
||||
|
||||
- `ncp-uart-sw_6.5.5_115200.ota` - legacy version for EZSP v7 compatible hosts.
|
||||
|
||||
## EmberZNet and EZSP Protocol Versions
|
||||
|
||||
|
|
Loading…
Reference in New Issue