mirror of https://github.com/arendst/Tasmota.git
Scripter update (#18578)
* add ds2480b library * add onewire support * reset on error * call to get esp32 HWS * DS2480 serial invert option
This commit is contained in:
parent
13de7a4863
commit
687b26ad13
|
@ -64,6 +64,7 @@ class TasmotaSerial : public Stream {
|
|||
uint32_t getLoopReadMetric(void) const { return m_bit_follow_metric; }
|
||||
#ifdef ESP32
|
||||
uint32_t getUart(void) const { return m_uart; }
|
||||
HardwareSerial *getesp32hws(void) { return TSerial; }
|
||||
#endif
|
||||
bool isValid(void) { return m_valid; }
|
||||
bool overflow(void);
|
||||
|
|
|
@ -0,0 +1,569 @@
|
|||
/*
|
||||
Copyright (c) 2007, Jim Studt (original old version - many contributors since)
|
||||
|
||||
This library based on OneWire library currently maintained by Paul Stoffregen. However,
|
||||
it has been modified to use the DS2480B serial to 1-wire chip instead of direct
|
||||
bitbanging on a digital pin. Also, it is unfortunately hard coded to use the AltSoftSerial library
|
||||
since this library has no common ancestor with the hardware serial class and there isn't a good way
|
||||
to allow use of either
|
||||
|
||||
OneWire has been maintained by Paul Stoffregen (paul@pjrc.com) since
|
||||
January 2010. At the time, it was in need of many bug fixes, but had
|
||||
been abandoned the original author (Jim Studt). None of the known
|
||||
contributors were interested in maintaining OneWire. Paul typically
|
||||
works on OneWire every 6 to 12 months. Patches usually wait that
|
||||
long. If anyone is interested in more actively maintaining OneWire,
|
||||
please contact Paul.
|
||||
|
||||
Version 2.2:
|
||||
Teensy 3.0 compatibility, Paul Stoffregen, paul@pjrc.com
|
||||
Arduino Due compatibility, http://arduino.cc/forum/index.php?topic=141030
|
||||
Fix DS18B20 example negative temperature
|
||||
Fix DS18B20 example's low res modes, Ken Butcher
|
||||
Improve reset timing, Mark Tillotson
|
||||
Add const qualifiers, Bertrik Sikken
|
||||
Add initial value input to crc16, Bertrik Sikken
|
||||
Add target_search() function, Scott Roberts
|
||||
|
||||
Version 2.1:
|
||||
Arduino 1.0 compatibility, Paul Stoffregen
|
||||
Improve temperature example, Paul Stoffregen
|
||||
DS250x_PROM example, Guillermo Lovato
|
||||
PIC32 (chipKit) compatibility, Jason Dangel, dangel.jason AT gmail.com
|
||||
Improvements from Glenn Trewitt:
|
||||
- crc16() now works
|
||||
- check_crc16() does all of calculation/checking work.
|
||||
- Added read_bytes() and write_bytes(), to reduce tedious loops.
|
||||
- Added ds2408 example.
|
||||
Delete very old, out-of-date readme file (info is here)
|
||||
|
||||
Version 2.0: Modifications by Paul Stoffregen, January 2010:
|
||||
http://www.pjrc.com/teensy/td_libs_OneWire.html
|
||||
Search fix from Robin James
|
||||
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27
|
||||
Use direct optimized I/O in all cases
|
||||
Disable interrupts during timing critical sections
|
||||
(this solves many random communication errors)
|
||||
Disable interrupts during read-modify-write I/O
|
||||
Reduce RAM consumption by eliminating unnecessary
|
||||
variables and trimming many to 8 bits
|
||||
Optimize both crc8 - table version moved to flash
|
||||
|
||||
Modified to work with larger numbers of devices - avoids loop.
|
||||
Tested in Arduino 11 alpha with 12 sensors.
|
||||
26 Sept 2008 -- Robin James
|
||||
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27
|
||||
|
||||
Updated to work with arduino-0008 and to include skip() as of
|
||||
2007/07/06. --RJL20
|
||||
|
||||
Modified to calculate the 8-bit CRC directly, avoiding the need for
|
||||
the 256-byte lookup table to be loaded in RAM. Tested in arduino-0010
|
||||
-- Tom Pollard, Jan 23, 2008
|
||||
|
||||
Jim Studt's original library was modified by Josh Larios.
|
||||
|
||||
Tom Pollard, pollard@alum.mit.edu, contributed around May 20, 2008
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Much of the code was inspired by Derek Yerger's code, though I don't
|
||||
think much of that remains. In any event that was..
|
||||
(copyleft) 2006 by Derek Yerger - Free to distribute freely.
|
||||
|
||||
The CRC code was excerpted and inspired by the Dallas Semiconductor
|
||||
sample code bearing this copyright.
|
||||
//---------------------------------------------------------------------------
|
||||
// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// Except as contained in this notice, the name of Dallas Semiconductor
|
||||
// shall not be used except as stated in the Dallas Semiconductor
|
||||
// Branding Policy.
|
||||
//--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "DS2480B.h"
|
||||
|
||||
|
||||
DS2480B::DS2480B(TasmotaSerial *port)
|
||||
{
|
||||
_port = port;
|
||||
#if ONEWIRE_SEARCH
|
||||
reset_search();
|
||||
#endif
|
||||
}
|
||||
|
||||
void DS2480B::begin()
|
||||
{
|
||||
_port->write(0xC1);
|
||||
if (!waitForReply()) return;
|
||||
_port->read();
|
||||
isCmdMode = true;
|
||||
}
|
||||
|
||||
|
||||
// Perform the onewire reset function. We will wait up to 250uS for
|
||||
// the bus to come high, if it doesn't then it is broken or shorted
|
||||
// and we return a 0;
|
||||
//
|
||||
// Returns 1 if a device asserted a presence pulse, 0 otherwise.
|
||||
//
|
||||
uint8_t DS2480B::reset(void)
|
||||
{
|
||||
uint8_t r;
|
||||
|
||||
commandMode();
|
||||
|
||||
_port->write(0xC1);
|
||||
//proper return is 0xCD otherwise something was wrong
|
||||
//while (!_port->available());
|
||||
if (!waitForReply()) return true;
|
||||
|
||||
r = _port->read();
|
||||
if (r == 0xCD) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DS2480B::dataMode()
|
||||
{
|
||||
if (isCmdMode)
|
||||
{
|
||||
_port->write(DATA_MODE);
|
||||
isCmdMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DS2480B::commandMode()
|
||||
{
|
||||
if (!isCmdMode)
|
||||
{
|
||||
_port->write(COMMAND_MODE);
|
||||
isCmdMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DS2480B::beginTransaction()
|
||||
{
|
||||
dataMode();
|
||||
}
|
||||
|
||||
void DS2480B::endTransaction()
|
||||
{
|
||||
commandMode();
|
||||
}
|
||||
|
||||
#define DS2480_DELAY 50
|
||||
|
||||
bool DS2480B::waitForReply() {
|
||||
for (uint16_t i = 0; i < DS2480_DELAY; i++) {
|
||||
if (_port->available()) return true;
|
||||
delay(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Write a bit - actually returns the bit read back in case you care.
|
||||
//
|
||||
uint8_t DS2480B::write_bit(uint8_t v)
|
||||
{
|
||||
uint8_t val;
|
||||
commandMode();
|
||||
if (v == 1) _port->write(0x91); //write a single "on" bit to onewire
|
||||
else _port->write(0x81); //write a single "off" bit to onewire
|
||||
if (!waitForReply()) return 0;
|
||||
val = _port->read();
|
||||
return val & 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Read a bit - short hand for writing a 1 and seeing what we get back.
|
||||
//
|
||||
uint8_t DS2480B::read_bit(void)
|
||||
{
|
||||
uint8_t r = write_bit(1);
|
||||
return r;
|
||||
}
|
||||
|
||||
//
|
||||
// Write a byte. The writing code uses the active drivers to raise the
|
||||
// pin high, if you need power after the write (e.g. DS18S20 in
|
||||
// parasite power mode) then set 'power' to 1, otherwise the pin will
|
||||
// go tri-state at the end of the write to avoid heating in a short or
|
||||
// other mishap. - Currently power isn't actually used now.
|
||||
//
|
||||
void DS2480B::write(uint8_t v, uint8_t power /* = 0 */) {
|
||||
uint8_t r;
|
||||
|
||||
dataMode();
|
||||
|
||||
_port->write(v);
|
||||
//need to double up transmission if the sent byte was one of the command bytes
|
||||
if (v == DATA_MODE || v == COMMAND_MODE || v == PULSE_TERM) _port->write(v);
|
||||
if (!waitForReply()) return;
|
||||
r = _port->read(); //throw away reply
|
||||
}
|
||||
|
||||
void DS2480B::writeCmd(uint8_t v, uint8_t power)
|
||||
{
|
||||
uint8_t r;
|
||||
|
||||
commandMode();
|
||||
|
||||
_port->write(v);
|
||||
|
||||
if (!waitForReply()) return;
|
||||
r = _port->read(); //throw away reply
|
||||
}
|
||||
|
||||
void DS2480B::write_bytes(const uint8_t *buf, uint16_t count, bool power /* = 0 */) {
|
||||
for (uint16_t i = 0 ; i < count ; i++) write(buf[i]);
|
||||
}
|
||||
|
||||
//
|
||||
// Read a byte
|
||||
//
|
||||
uint8_t DS2480B::read() {
|
||||
uint8_t r;
|
||||
|
||||
dataMode();
|
||||
|
||||
_port->write(0xFF);
|
||||
if (!waitForReply()) return 0;
|
||||
r = _port->read();
|
||||
return r;
|
||||
}
|
||||
|
||||
void DS2480B::read_bytes(uint8_t *buf, uint16_t count) {
|
||||
for (uint16_t i = 0 ; i < count ; i++)
|
||||
buf[i] = read();
|
||||
}
|
||||
|
||||
//
|
||||
// Do a ROM select
|
||||
//
|
||||
void DS2480B::select(const uint8_t rom[8])
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
dataMode();
|
||||
write(0x55); // Choose ROM
|
||||
|
||||
for (i = 0; i < 8; i++) write(rom[i]);
|
||||
}
|
||||
|
||||
//
|
||||
// Do a ROM skip
|
||||
//
|
||||
void DS2480B::skip()
|
||||
{
|
||||
dataMode();
|
||||
write(0xCC); // Skip ROM
|
||||
}
|
||||
|
||||
void DS2480B::depower()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#if ONEWIRE_SEARCH
|
||||
|
||||
//
|
||||
// You need to use this function to start a search again from the beginning.
|
||||
// You do not need to do it for the first search, though you could.
|
||||
//
|
||||
void DS2480B::reset_search()
|
||||
{
|
||||
// reset the search state
|
||||
LastDiscrepancy = 0;
|
||||
LastDeviceFlag = FALSE;
|
||||
LastFamilyDiscrepancy = 0;
|
||||
for(int i = 7; ; i--) {
|
||||
ROM_NO[i] = 0;
|
||||
if ( i == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the search to find the device type 'family_code' on the next call
|
||||
// to search(*newAddr) if it is present.
|
||||
//
|
||||
void DS2480B::target_search(uint8_t family_code)
|
||||
{
|
||||
// set the search state to find SearchFamily type devices
|
||||
ROM_NO[0] = family_code;
|
||||
for (uint8_t i = 1; i < 8; i++)
|
||||
ROM_NO[i] = 0;
|
||||
LastDiscrepancy = 64;
|
||||
LastFamilyDiscrepancy = 0;
|
||||
LastDeviceFlag = FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Perform a search. If this function returns a '1' then it has
|
||||
// enumerated the next device and you may retrieve the ROM from the
|
||||
// DS2480B::address variable. If there are no devices, no further
|
||||
// devices, or something horrible happens in the middle of the
|
||||
// enumeration then a 0 is returned. If a new device is found then
|
||||
// its address is copied to newAddr. Use DS2480B::reset_search() to
|
||||
// start over.
|
||||
//
|
||||
// --- Replaced by the one from the Dallas Semiconductor web site ---
|
||||
//--------------------------------------------------------------------------
|
||||
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
|
||||
// search state.
|
||||
// Return TRUE : device found, ROM number in ROM_NO buffer
|
||||
// FALSE : device not found, end of search
|
||||
//
|
||||
uint8_t DS2480B::search(uint8_t *newAddr)
|
||||
{
|
||||
uint8_t id_bit_number;
|
||||
uint8_t last_zero, rom_byte_number, search_result;
|
||||
uint8_t id_bit, cmp_id_bit;
|
||||
|
||||
unsigned char rom_byte_mask, search_direction;
|
||||
|
||||
// initialize for search
|
||||
id_bit_number = 1;
|
||||
last_zero = 0;
|
||||
rom_byte_number = 0;
|
||||
rom_byte_mask = 1;
|
||||
search_result = 0;
|
||||
|
||||
// if the last call was not the last one
|
||||
if (!LastDeviceFlag)
|
||||
{
|
||||
// 1-Wire reset
|
||||
if (!reset())
|
||||
{
|
||||
// reset the search
|
||||
LastDiscrepancy = 0;
|
||||
LastDeviceFlag = FALSE;
|
||||
LastFamilyDiscrepancy = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// issue the search command
|
||||
write(0xF0); //send search command to DS18B20 units
|
||||
|
||||
// loop to do the search
|
||||
do
|
||||
{
|
||||
// read a bit and its complement
|
||||
id_bit = read_bit();
|
||||
cmp_id_bit = read_bit();
|
||||
|
||||
// check for no devices on 1-wire
|
||||
if ((id_bit == 1) && (cmp_id_bit == 1))
|
||||
break;
|
||||
else
|
||||
{
|
||||
// all devices coupled have 0 or 1
|
||||
if (id_bit != cmp_id_bit)
|
||||
search_direction = id_bit; // bit write value for search
|
||||
else
|
||||
{
|
||||
// if this discrepancy if before the Last Discrepancy
|
||||
// on a previous next then pick the same as last time
|
||||
if (id_bit_number < LastDiscrepancy)
|
||||
search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
|
||||
else
|
||||
// if equal to last pick 1, if not then pick 0
|
||||
search_direction = (id_bit_number == LastDiscrepancy);
|
||||
|
||||
// if 0 was picked then record its position in LastZero
|
||||
if (search_direction == 0)
|
||||
{
|
||||
last_zero = id_bit_number;
|
||||
|
||||
// check for Last discrepancy in family
|
||||
if (last_zero < 9)
|
||||
LastFamilyDiscrepancy = last_zero;
|
||||
}
|
||||
}
|
||||
|
||||
// set or clear the bit in the ROM byte rom_byte_number
|
||||
// with mask rom_byte_mask
|
||||
if (search_direction == 1)
|
||||
ROM_NO[rom_byte_number] |= rom_byte_mask;
|
||||
else
|
||||
ROM_NO[rom_byte_number] &= ~rom_byte_mask;
|
||||
|
||||
// serial number search direction write bit
|
||||
write_bit(search_direction);
|
||||
|
||||
// increment the byte counter id_bit_number
|
||||
// and shift the mask rom_byte_mask
|
||||
id_bit_number++;
|
||||
rom_byte_mask <<= 1;
|
||||
|
||||
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
|
||||
if (rom_byte_mask == 0)
|
||||
{
|
||||
rom_byte_number++;
|
||||
rom_byte_mask = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
while(rom_byte_number < 8); // loop until through all ROM bytes 0-7
|
||||
|
||||
// if the search was successful then
|
||||
if (!(id_bit_number < 65))
|
||||
{
|
||||
// search successful so set LastDiscrepancy,LastDeviceFlag,search_result
|
||||
LastDiscrepancy = last_zero;
|
||||
|
||||
// check for last device
|
||||
if (LastDiscrepancy == 0)
|
||||
LastDeviceFlag = TRUE;
|
||||
|
||||
search_result = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// if no device found then reset counters so next 'search' will be like a first
|
||||
if (!search_result || !ROM_NO[0])
|
||||
{
|
||||
LastDiscrepancy = 0;
|
||||
LastDeviceFlag = FALSE;
|
||||
LastFamilyDiscrepancy = 0;
|
||||
search_result = FALSE;
|
||||
}
|
||||
for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i];
|
||||
return search_result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if ONEWIRE_CRC
|
||||
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
|
||||
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
|
||||
//
|
||||
|
||||
#if ONEWIRE_CRC8_TABLE
|
||||
// This table comes from Dallas sample code where it is freely reusable,
|
||||
// though Copyright (C) 2000 Dallas Semiconductor Corporation
|
||||
static const uint8_t PROGMEM dscrc_table[] = {
|
||||
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
|
||||
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
|
||||
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
|
||||
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
|
||||
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
|
||||
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
|
||||
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
|
||||
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
|
||||
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
|
||||
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
|
||||
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
|
||||
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
|
||||
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
|
||||
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
|
||||
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
|
||||
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};
|
||||
|
||||
//
|
||||
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
|
||||
// and the registers. (note: this might better be done without to
|
||||
// table, it would probably be smaller and certainly fast enough
|
||||
// compared to all those delayMicrosecond() calls. But I got
|
||||
// confused, so I use this table from the examples.)
|
||||
//
|
||||
uint8_t DS2480B::crc8(const uint8_t *addr, uint8_t len)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
crc = pgm_read_byte(dscrc_table + (crc ^ *addr++));
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#else
|
||||
//
|
||||
// Compute a Dallas Semiconductor 8 bit CRC directly.
|
||||
// this is much slower, but much smaller, than the lookup table.
|
||||
//
|
||||
uint8_t DS2480B::crc8(const uint8_t *addr, uint8_t len)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
uint8_t inbyte = *addr++;
|
||||
for (uint8_t i = 8; i; i--) {
|
||||
uint8_t mix = (crc ^ inbyte) & 0x01;
|
||||
crc >>= 1;
|
||||
if (mix) crc ^= 0x8C;
|
||||
inbyte >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ONEWIRE_CRC16
|
||||
bool DS2480B::check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc)
|
||||
{
|
||||
crc = ~crc16(input, len, crc);
|
||||
return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1];
|
||||
}
|
||||
|
||||
uint16_t DS2480B::crc16(const uint8_t* input, uint16_t len, uint16_t crc)
|
||||
{
|
||||
static const uint8_t oddparity[16] =
|
||||
{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
|
||||
|
||||
for (uint16_t i = 0 ; i < len ; i++) {
|
||||
// Even though we're just copying a byte from the input,
|
||||
// we'll be doing 16-bit computation with it.
|
||||
uint16_t cdata = input[i];
|
||||
cdata = (cdata ^ crc) & 0xff;
|
||||
crc >>= 8;
|
||||
|
||||
if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4])
|
||||
crc ^= 0xC001;
|
||||
|
||||
cdata <<= 6;
|
||||
crc ^= cdata;
|
||||
cdata <<= 1;
|
||||
crc ^= cdata;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,200 @@
|
|||
#ifndef DS2480B_h
|
||||
#define DS2480B_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h" // for delayMicroseconds, digitalPinToBitMask, etc
|
||||
#else
|
||||
#include "WProgram.h" // for delayMicroseconds
|
||||
#include "pins_arduino.h" // for digitalPinToBitMask, etc
|
||||
#endif
|
||||
|
||||
#include <TasmotaSerial.h>
|
||||
|
||||
// You can exclude certain features from OneWire. In theory, this
|
||||
// might save some space. In practice, the compiler automatically
|
||||
// removes unused code (technically, the linker, using -fdata-sections
|
||||
// and -ffunction-sections when compiling, and Wl,--gc-sections
|
||||
// when linking), so most of these will not result in any code size
|
||||
// reduction. Well, unless you try to use the missing features
|
||||
// and redesign your program to not need them! ONEWIRE_CRC8_TABLE
|
||||
// is the exception, because it selects a fast but large algorithm
|
||||
// or a small but slow algorithm.
|
||||
|
||||
// you can exclude onewire_search by defining that to 0
|
||||
#ifndef ONEWIRE_SEARCH
|
||||
#define ONEWIRE_SEARCH 1
|
||||
#endif
|
||||
|
||||
// You can exclude CRC checks altogether by defining this to 0
|
||||
#ifndef ONEWIRE_CRC
|
||||
#define ONEWIRE_CRC 1
|
||||
#endif
|
||||
|
||||
// Select the table-lookup method of computing the 8-bit CRC
|
||||
// by setting this to 1. The lookup table enlarges code size by
|
||||
// about 250 bytes. It does NOT consume RAM (but did in very
|
||||
// old versions of OneWire). If you disable this, a slower
|
||||
// but very compact algorithm is used.
|
||||
#ifndef ONEWIRE_CRC8_TABLE
|
||||
#define ONEWIRE_CRC8_TABLE 1
|
||||
#endif
|
||||
|
||||
// You can allow 16-bit CRC checks by defining this to 1
|
||||
// (Note that ONEWIRE_CRC must also be 1.)
|
||||
#ifndef ONEWIRE_CRC16
|
||||
#define ONEWIRE_CRC16 1
|
||||
#endif
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
// Platform specific I/O definitions
|
||||
|
||||
#if defined(__AVR__)
|
||||
#elif defined(__MK20DX128__)
|
||||
#elif defined(__SAM3X8E__)
|
||||
#ifndef PROGMEM
|
||||
#define PROGMEM
|
||||
#endif
|
||||
#ifndef pgm_read_byte
|
||||
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
|
||||
#endif
|
||||
#elif defined(__PIC32MX__)
|
||||
#else
|
||||
#endif
|
||||
|
||||
#define DATA_MODE 0xE1
|
||||
#define COMMAND_MODE 0xE3
|
||||
#define PULSE_TERM 0xF1
|
||||
|
||||
class DS2480B
|
||||
{
|
||||
private:
|
||||
TasmotaSerial *_port;
|
||||
bool isCmdMode;
|
||||
|
||||
#if ONEWIRE_SEARCH
|
||||
// global search state
|
||||
unsigned char ROM_NO[8];
|
||||
uint8_t LastDiscrepancy;
|
||||
uint8_t LastFamilyDiscrepancy;
|
||||
uint8_t LastDeviceFlag;
|
||||
#endif
|
||||
|
||||
bool waitForReply();
|
||||
|
||||
public:
|
||||
DS2480B(TasmotaSerial *port);
|
||||
|
||||
void begin();
|
||||
|
||||
// Perform a 1-Wire reset cycle. Returns 1 if a device responds
|
||||
// with a presence pulse. Returns 0 if there is no device or the
|
||||
// bus is shorted or otherwise held low for more than 250uS
|
||||
uint8_t reset(void);
|
||||
|
||||
void beginTransaction();
|
||||
void endTransaction();
|
||||
|
||||
void commandMode();
|
||||
void dataMode();
|
||||
|
||||
// Issue a 1-Wire rom select command, you do the reset first.
|
||||
void select(const uint8_t rom[8]);
|
||||
|
||||
// Issue a 1-Wire rom skip command, to address all on bus.
|
||||
void skip(void);
|
||||
|
||||
// Write a byte. If 'power' is one then the wire is held high at
|
||||
// the end for parasitically powered devices. You are responsible
|
||||
// for eventually depowering it by calling depower() or doing
|
||||
// another read or write.
|
||||
void write(uint8_t v, uint8_t power = 0);
|
||||
|
||||
void writeCmd(uint8_t v, uint8_t power = 0);
|
||||
|
||||
void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0);
|
||||
|
||||
// Read a byte.
|
||||
uint8_t read(void);
|
||||
|
||||
void read_bytes(uint8_t *buf, uint16_t count);
|
||||
|
||||
// Write a bit.
|
||||
uint8_t write_bit(uint8_t v);
|
||||
|
||||
// Read a bit.
|
||||
uint8_t read_bit(void);
|
||||
|
||||
// Stop forcing power onto the bus. You only need to do this if
|
||||
// you used the 'power' flag to write() or used a write_bit() call
|
||||
// and aren't about to do another read or write. You would rather
|
||||
// not leave this powered if you don't have to, just in case
|
||||
// someone shorts your bus.
|
||||
void depower(void);
|
||||
|
||||
#if ONEWIRE_SEARCH
|
||||
// Clear the search state so that if will start from the beginning again.
|
||||
void reset_search();
|
||||
|
||||
// Setup the search to find the device type 'family_code' on the next call
|
||||
// to search(*newAddr) if it is present.
|
||||
void target_search(uint8_t family_code);
|
||||
|
||||
// Look for the next device. Returns 1 if a new address has been
|
||||
// returned. A zero might mean that the bus is shorted, there are
|
||||
// no devices, or you have already retrieved all of them. It
|
||||
// might be a good idea to check the CRC to make sure you didn't
|
||||
// get garbage. The order is deterministic. You will always get
|
||||
// the same devices in the same order.
|
||||
uint8_t search(uint8_t *newAddr);
|
||||
#endif
|
||||
|
||||
#if ONEWIRE_CRC
|
||||
// Compute a Dallas Semiconductor 8 bit CRC, these are used in the
|
||||
// ROM and scratchpad registers.
|
||||
static uint8_t crc8(const uint8_t *addr, uint8_t len);
|
||||
|
||||
#if ONEWIRE_CRC16
|
||||
// Compute the 1-Wire CRC16 and compare it against the received CRC.
|
||||
// Example usage (reading a DS2408):
|
||||
// // Put everything in a buffer so we can compute the CRC easily.
|
||||
// uint8_t buf[13];
|
||||
// buf[0] = 0xF0; // Read PIO Registers
|
||||
// buf[1] = 0x88; // LSB address
|
||||
// buf[2] = 0x00; // MSB address
|
||||
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
|
||||
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
|
||||
// if (!CheckCRC16(buf, 11, &buf[11])) {
|
||||
// // Handle error.
|
||||
// }
|
||||
//
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param inverted_crc - The two CRC16 bytes in the received data.
|
||||
// This should just point into the received data,
|
||||
// *not* at a 16-bit integer.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return True, iff the CRC matches.
|
||||
static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0);
|
||||
|
||||
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
|
||||
// the integrity of data received from many 1-Wire devices. Note that the
|
||||
// CRC computed here is *not* what you'll get from the 1-Wire network,
|
||||
// for two reasons:
|
||||
// 1) The CRC is transmitted bitwise inverted.
|
||||
// 2) Depending on the endian-ness of your processor, the binary
|
||||
// representation of the two-byte return value may have a different
|
||||
// byte order than the two bytes you get from 1-Wire.
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return The CRC16, as defined by Dallas Semiconductor.
|
||||
static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0);
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
DS2480B Library for Arduino
|
||||
=======================
|
||||
|
||||
Interfaces with DS2480B chip in order
|
||||
to acquire access to the 1-wire bus over
|
||||
serial
|
|
@ -0,0 +1,123 @@
|
|||
#include <DS2480B.h>
|
||||
|
||||
// OneWire DS18S20, DS18B20, DS1822 Temperature Example
|
||||
//
|
||||
// http://www.pjrc.com/teensy/td_libs_OneWire.html
|
||||
//
|
||||
// The DallasTemperature library can do all this work for you!
|
||||
// http://milesburton.com/Dallas_Temperature_Control_Library
|
||||
|
||||
|
||||
#include <AltSoftSerial.h>
|
||||
|
||||
AltSoftSerial altSerial; //RX 8 - TX 9
|
||||
|
||||
DS2480B ds(altSerial);
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
altSerial.begin(9600);
|
||||
ds.begin();
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
byte i;
|
||||
byte present = 0;
|
||||
byte type_s;
|
||||
byte data[12];
|
||||
byte addr[8];
|
||||
float celsius, fahrenheit;
|
||||
|
||||
if ( !ds.search(addr)) {
|
||||
Serial.println("No more addresses.");
|
||||
Serial.println();
|
||||
ds.reset_search();
|
||||
delay(5000);
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.print("ROM =");
|
||||
for( i = 0; i < 8; i++) {
|
||||
Serial.write(' ');
|
||||
Serial.print(addr[i], HEX);
|
||||
}
|
||||
|
||||
if (DS2480B::crc8(addr, 7) != addr[7]) {
|
||||
Serial.println("CRC is not valid!");
|
||||
return;
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
// the first ROM byte indicates which chip
|
||||
switch (addr[0]) {
|
||||
case 0x10:
|
||||
Serial.println(" Chip = DS18S20"); // or old DS1820
|
||||
type_s = 1;
|
||||
break;
|
||||
case 0x28:
|
||||
Serial.println(" Chip = DS18B20");
|
||||
type_s = 0;
|
||||
break;
|
||||
case 0x22:
|
||||
Serial.println(" Chip = DS1822");
|
||||
type_s = 0;
|
||||
break;
|
||||
default:
|
||||
Serial.println("Device is not a DS18x20 family device.");
|
||||
return;
|
||||
}
|
||||
|
||||
ds.reset();
|
||||
|
||||
delay(100);
|
||||
|
||||
ds.reset();
|
||||
ds.select(addr);
|
||||
ds.write(0x44); // start conversion
|
||||
|
||||
delay(1000); // maybe 750ms is enough, maybe not
|
||||
// we might do a ds.depower() here, but the reset will take care of it.
|
||||
|
||||
present = ds.reset();
|
||||
ds.select(addr);
|
||||
ds.write(0xBE); // Read Scratchpad
|
||||
|
||||
Serial.print(" Data = ");
|
||||
Serial.print(present, HEX);
|
||||
Serial.print(" ");
|
||||
for ( i = 0; i < 9; i++) { // we need 9 bytes
|
||||
data[i] = ds.read();
|
||||
Serial.print(data[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.print(" CRC=");
|
||||
Serial.print(DS2480B::crc8(data, 8), HEX);
|
||||
Serial.println();
|
||||
|
||||
// Convert the data to actual temperature
|
||||
// because the result is a 16 bit signed integer, it should
|
||||
// be stored to an "int16_t" type, which is always 16 bits
|
||||
// even when compiled on a 32 bit processor.
|
||||
int16_t raw = (data[1] << 8) | data[0];
|
||||
if (type_s) {
|
||||
raw = raw << 3; // 9 bit resolution default
|
||||
if (data[7] == 0x10) {
|
||||
// "count remain" gives full 12 bit resolution
|
||||
raw = (raw & 0xFFF0) + 12 - data[6];
|
||||
}
|
||||
} else {
|
||||
byte cfg = (data[4] & 0x60);
|
||||
// at lower res, the low bits are undefined, so let's zero them
|
||||
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
|
||||
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
|
||||
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
|
||||
//// default is 12 bit resolution, 750 ms conversion time
|
||||
}
|
||||
celsius = (float)raw / 16.0;
|
||||
fahrenheit = celsius * 1.8 + 32.0;
|
||||
Serial.print(" Temperature = ");
|
||||
Serial.print(celsius);
|
||||
Serial.print(" Celsius, ");
|
||||
Serial.print(fahrenheit);
|
||||
Serial.println(" Fahrenheit");
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For DS2480B
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
RTC_clock KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
init KEYWORD2
|
||||
set_time KEYWORD2
|
||||
set_date KEYWORD2
|
||||
set_seconds KEYWORD2
|
||||
set_minutes KEYWORD2
|
||||
set_hours KEYWORD2
|
||||
set_days KEYWORD2
|
||||
set_months KEYWORD2
|
||||
set_years KEYWORD2
|
||||
set_alarmtime KEYWORD2
|
||||
set_alarmdate KEYWORD2
|
||||
get_seconds KEYWORD2
|
||||
get_minutes KEYWORD2
|
||||
get_hours KEYWORD2
|
||||
get_days KEYWORD2
|
||||
get_day_of_week KEYWORD2
|
||||
get_months KEYWORD2
|
||||
get_years KEYWORD2
|
||||
attachalarm KEYWORD2
|
||||
disable_alarm KEYWORD2
|
||||
unixtime KEYWORD2
|
||||
get_time KEYWORD2
|
||||
get_date KEYWORD2
|
||||
summertime KEYWORD2
|
||||
switch_years KEYWORD2
|
||||
timing KEYWORD2
|
||||
date_already_set KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
|
||||
#######################################
|
||||
# Mean Instances (KEYWORD3)
|
||||
#######################################
|
||||
|
||||
rtc_clock KEYWORD3
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
RC LITERAL1
|
||||
XTAL LITERAL1
|
||||
|
||||
__TIME__ LITERAL1
|
||||
__DATE__ LITERAL1
|
||||
|
||||
Germany LITERAL1
|
|
@ -0,0 +1,9 @@
|
|||
name=DS2480 Library
|
||||
version=0.1.0
|
||||
author=Jim Studt
|
||||
maintainer=Jim Studt
|
||||
sentence=DS2480
|
||||
paragraph=DS2480
|
||||
category=Communication
|
||||
architectures=*
|
||||
includes=DS2408.h
|
|
@ -24,6 +24,7 @@ class Powerwall {
|
|||
String GetRequest(String url, String authCookie);
|
||||
String GetRequest(String url);
|
||||
String AuthCookie();
|
||||
void resetAuthCookie();
|
||||
};
|
||||
|
||||
|
||||
|
@ -37,6 +38,9 @@ Powerwall::Powerwall() {
|
|||
String Powerwall::AuthCookie() {
|
||||
return authCookie;
|
||||
}
|
||||
void Powerwall::resetAuthCookie() {
|
||||
authCookie = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns a string with the authToken based on the basic login endpoint of
|
||||
|
@ -165,6 +169,7 @@ String Powerwall::GetRequest(String url, String authCookie) {
|
|||
// in case of error 401, get new cookie
|
||||
if (result == 401) {
|
||||
authCookie = "";
|
||||
resetAuthCookie();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,11 +46,10 @@ keywords if then else endif, or, and are better readable for beginners (others m
|
|||
#ifndef TS_FLOAT
|
||||
#define TS_FLOAT float
|
||||
#endif
|
||||
|
||||
|
||||
// float = 4, double = 8 bytes
|
||||
|
||||
const uint8_t SCRIPT_VERS[2] = {5, 1};
|
||||
|
||||
const uint8_t SCRIPT_VERS[2] = {5, 2};
|
||||
|
||||
#define SCRIPT_DEBUG 0
|
||||
|
||||
|
@ -190,6 +189,8 @@ void Script_ticker4_end(void) {
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// EEPROM MACROS
|
||||
// i2c eeprom
|
||||
#define EEP_WRITE(A,B,C) eeprom_writeBytes(A, B, (uint8_t*)C);
|
||||
|
@ -439,6 +440,22 @@ struct SCRIPT_SPI {
|
|||
#define FLT_MAX 99999999
|
||||
#endif
|
||||
|
||||
#ifdef USE_SCRIPT_ONEWIRE
|
||||
#include <OneWire.h>
|
||||
#include <DS2480B.h>
|
||||
|
||||
#ifndef MAX_DS_SENSORS
|
||||
#define MAX_DS_SENSORS 20
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
OneWire *ds;
|
||||
DS2480B *dsh;
|
||||
TasmotaSerial *ts;
|
||||
uint8_t ds_address[MAX_DS_SENSORS][8];
|
||||
} ScriptOneWire;
|
||||
#endif // USE_SCRIPT_ONEWIRE
|
||||
|
||||
#define SFS_MAX 4
|
||||
// global memory
|
||||
struct SCRIPT_MEM {
|
||||
|
@ -499,6 +516,7 @@ struct SCRIPT_MEM {
|
|||
char *web_pages[10];
|
||||
uint32_t script_lastmillis;
|
||||
bool event_handeled = false;
|
||||
bool res_ivar = false;
|
||||
#ifdef USE_BUTTON_EVENT
|
||||
int8_t script_button[MAX_KEYS];
|
||||
#endif //USE_BUTTON_EVENT
|
||||
|
@ -523,6 +541,15 @@ struct SCRIPT_MEM {
|
|||
char *hstr;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SCRIPT_I2C
|
||||
uint8_t script_i2c_addr;
|
||||
TwoWire *script_i2c_wire;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SCRIPT_ONEWIRE
|
||||
ScriptOneWire ow;
|
||||
#endif
|
||||
|
||||
} glob_script_mem;
|
||||
|
||||
|
||||
|
@ -533,10 +560,10 @@ void flt2char(TS_FLOAT num, char *nbuff) {
|
|||
dtostrfd(num, glob_script_mem.script_dprec, nbuff);
|
||||
}
|
||||
|
||||
void f2char(TS_FLOAT num, uint32_t dprec, uint32_t lzeros, char *nbuff, char dsep);
|
||||
void f2char(double num, uint32_t dprec, uint32_t lzeros, char *nbuff, char dsep);
|
||||
|
||||
// convert float to char with leading zeros
|
||||
void f2char(TS_FLOAT num, uint32_t dprec, uint32_t lzeros, char *nbuff, char dsep) {
|
||||
void f2char(double num, uint32_t dprec, uint32_t lzeros, char *nbuff, char dsep) {
|
||||
dtostrfd(num, dprec, nbuff);
|
||||
if (lzeros > 1) {
|
||||
// check leading zeros
|
||||
|
@ -583,6 +610,8 @@ int32_t opt_fext(File *fp, char *ts_from, char *ts_to, uint32_t flg);
|
|||
int32_t extract_from_file(File *fp, char *ts_from, char *ts_to, int8_t coffs, TS_FLOAT **a_ptr, uint16_t *a_len, uint8_t numa, int16_t accum);
|
||||
#endif
|
||||
char *eval_sub(char *lp, TS_FLOAT *fvar, char *rstr);
|
||||
uint32_t script_ow(uint8_t sel, uint32_t val);
|
||||
int32_t script_logfile_write(char *path, char *payload, uint32_t size);
|
||||
|
||||
void ScriptEverySecond(void) {
|
||||
|
||||
|
@ -2296,6 +2325,33 @@ uint32_t match_vars(char *dvnam, TS_FLOAT **fp, char **sp, uint32_t *ind) {
|
|||
#define SCRIPT_IS_STRING_MAXSIZE 256
|
||||
#endif
|
||||
|
||||
|
||||
void script_sort_string_array(uint8_t num) {
|
||||
uint16_t sasize = glob_script_mem.si_num[num];
|
||||
char *sa = glob_script_mem.last_index_string[num];
|
||||
if (!sa) {
|
||||
return;
|
||||
}
|
||||
char temp[SCRIPT_MAXSSIZE];
|
||||
bool swapped;
|
||||
do {
|
||||
swapped = false;
|
||||
for (uint16_t i = 0; i < sasize - 1; ++i) {
|
||||
char *s1 = sa + (i * glob_script_mem.max_ssize);
|
||||
char *s2 = sa + ((i + 1) * glob_script_mem.max_ssize);
|
||||
if (strcmp(s1, s2) > 0) {
|
||||
// swap
|
||||
strcpy(temp, s1);
|
||||
strcpy(s1, s2);
|
||||
strcpy(s2, temp);
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
sasize -= 1;
|
||||
} while (swapped);
|
||||
}
|
||||
|
||||
|
||||
char *isargs(char *lp, uint32_t isind) {
|
||||
TS_FLOAT fvar;
|
||||
lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0);
|
||||
|
@ -2331,11 +2387,11 @@ char *isargs(char *lp, uint32_t isind) {
|
|||
glob_script_mem.si_num[isind] = MAX_SARRAY_NUM;
|
||||
}
|
||||
|
||||
glob_script_mem.last_index_string[isind] = (char*)calloc(glob_script_mem.max_ssize*glob_script_mem.si_num[isind], 1);
|
||||
for (uint32_t cnt = 0; cnt<glob_script_mem.siro_num[isind]; cnt++) {
|
||||
glob_script_mem.last_index_string[isind] = (char*)calloc(glob_script_mem.max_ssize * glob_script_mem.si_num[isind], 1);
|
||||
for (uint32_t cnt = 0; cnt < glob_script_mem.siro_num[isind]; cnt++) {
|
||||
char str[SCRIPT_MAXSSIZE];
|
||||
GetTextIndexed(str, sizeof(str), cnt, sstart);
|
||||
strlcpy(glob_script_mem.last_index_string[isind] + (cnt*glob_script_mem.max_ssize), str,glob_script_mem.max_ssize);
|
||||
strlcpy(glob_script_mem.last_index_string[isind] + (cnt * glob_script_mem.max_ssize), str, glob_script_mem.max_ssize);
|
||||
}
|
||||
} else {
|
||||
glob_script_mem.last_index_string[isind] = sstart;
|
||||
|
@ -2390,8 +2446,8 @@ TS_FLOAT fvar;
|
|||
GetTextIndexed(str, sizeof(str), index , glob_script_mem.last_index_string[isind]);
|
||||
}
|
||||
} else {
|
||||
if (index > glob_script_mem.si_num[isind]) {
|
||||
index = glob_script_mem.si_num[isind];
|
||||
if (index >= glob_script_mem.si_num[isind]) {
|
||||
index = glob_script_mem.si_num[isind] - 1;
|
||||
}
|
||||
strlcpy(str,glob_script_mem.last_index_string[isind] + (index * glob_script_mem.max_ssize), glob_script_mem.max_ssize);
|
||||
}
|
||||
|
@ -2449,6 +2505,7 @@ char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, TS_FLOAT *fp, char *
|
|||
// isnumber
|
||||
if (fp) {
|
||||
if (*lp == '0' && *(lp + 1) == 'x') {
|
||||
|
||||
lp += 2;
|
||||
*fp = strtoll(lp, &lp, 16);
|
||||
} else {
|
||||
|
@ -2466,6 +2523,8 @@ char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, TS_FLOAT *fp, char *
|
|||
return lp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (*lp == '"') {
|
||||
lp++;
|
||||
while (*lp != '"') {
|
||||
|
@ -2521,6 +2580,7 @@ char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, TS_FLOAT *fp, char *
|
|||
olen = strlen(dvnam);
|
||||
}
|
||||
|
||||
|
||||
glob_script_mem.arres = 0;
|
||||
for (count = 0; count < glob_script_mem.numvars; count++) {
|
||||
char *cp = glob_script_mem.glob_vnp + glob_script_mem.vnp_offset[count];
|
||||
|
@ -2558,6 +2618,7 @@ char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, TS_FLOAT *fp, char *
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#define USE_SCRIPT_JSON
|
||||
//#define USE_SCRIPT_FULL_JSON_PARSER
|
||||
|
||||
|
@ -2785,6 +2846,19 @@ chknext:
|
|||
goto nfuncexit;
|
||||
}
|
||||
|
||||
if (!strncmp_XP(lp, XPSTR("as("), 3)) {
|
||||
uint16_t alen;
|
||||
TS_FLOAT *fa;
|
||||
lp = get_array_by_name(lp + 3, &fa, &alen, 0);
|
||||
if (!fa) {
|
||||
fvar = -1;
|
||||
goto exit;
|
||||
}
|
||||
script_sort_array(fa, alen);
|
||||
fvar = 0;
|
||||
goto nfuncexit;
|
||||
}
|
||||
|
||||
if (!strncmp_XP(lp, XPSTR("af("), 3)) {
|
||||
// array to float
|
||||
uint16_t alend;
|
||||
|
@ -3022,6 +3096,10 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
|
|||
goto nfuncexit;
|
||||
}
|
||||
#endif
|
||||
if (!strncmp_XP(vname, XPSTR("ctper"), 5)) {
|
||||
fvar = TasmotaGlobal.tele_period;
|
||||
goto exit;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
if (!strncmp_XP(vname, XPSTR("day"), 3)) {
|
||||
|
@ -3268,6 +3346,13 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
|
|||
lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv);
|
||||
uint8_t find = fvar;
|
||||
if (find >= SFS_MAX) find = SFS_MAX - 1;
|
||||
while (*lp == ' ') lp++;
|
||||
uint8_t options = 0;
|
||||
if (*lp != ')') {
|
||||
// options
|
||||
lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv);
|
||||
options = fvar;
|
||||
}
|
||||
uint8_t index = 0;
|
||||
char str[SCRIPT_MAXSSIZE];
|
||||
char *cp = str;
|
||||
|
@ -3298,9 +3383,12 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
|
|||
while (glob_script_mem.files[find].available()) {
|
||||
uint8_t buf[1];
|
||||
glob_script_mem.files[find].read(buf,1);
|
||||
if (buf[0] == '\t' || buf[0] == ',' || buf[0] == '\n' || buf[0] == '\r') {
|
||||
if (!options && (buf[0] == '\t' || buf[0] == ',' || buf[0] == '\n' || buf[0] == '\r')) {
|
||||
break;
|
||||
} else {
|
||||
if (options && (buf[0] == '\n' || buf[0] == '\r')) {
|
||||
break;
|
||||
}
|
||||
*cp++ = buf[0];
|
||||
index++;
|
||||
if (index >= glob_script_mem.max_ssize - 1) break;
|
||||
|
@ -3679,6 +3767,13 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
|
|||
goto nfuncexit;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!strncmp_XP(lp, XPSTR("f("), 2)) {
|
||||
// convert to float var
|
||||
lp = GetNumericArgument(lp + 2, OPER_EQU, &fvar, gv);
|
||||
fvar = *(uint32_t*)&fvar;
|
||||
goto nfuncexit;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
|
@ -3732,7 +3827,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
|
|||
}
|
||||
} else {
|
||||
// preserve mqtt_data
|
||||
char *mqd = (char*)malloc(ResponseSize()+2);
|
||||
char *mqd = (char*)malloc(ResponseSize() + 2);
|
||||
if (mqd) {
|
||||
strlcpy(mqd, ResponseData(), ResponseSize());
|
||||
wd = mqd;
|
||||
|
@ -4025,7 +4120,11 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
|
|||
// arg2
|
||||
TS_FLOAT fvar2;
|
||||
lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv);
|
||||
fvar = script_i2c(9 + bytes, fvar, fvar2);
|
||||
if (glob_script_mem.res_ivar) {
|
||||
fvar = script_i2c(9 + bytes, fvar, *(uint32_t*)&fvar2);
|
||||
} else {
|
||||
fvar = script_i2c(9 + bytes, fvar, fvar2);
|
||||
}
|
||||
goto nfuncexit;
|
||||
}
|
||||
if (!strncmp_XP(lp, XPSTR("ir"), 2)) {
|
||||
|
@ -4038,7 +4137,12 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
|
|||
lp++;
|
||||
}
|
||||
lp = GetNumericArgument(lp + 1, OPER_EQU, &fvar, gv);
|
||||
fvar = script_i2c(2, fvar, bytes);
|
||||
if (glob_script_mem.res_ivar) {
|
||||
uint32_t intres = script_i2c(2, fvar, bytes);
|
||||
(*(uint32_t*)&fvar) = intres;
|
||||
} else {
|
||||
fvar = script_i2c(2, fvar, bytes);
|
||||
}
|
||||
goto nfuncexit;
|
||||
}
|
||||
#endif // USE_SCRIPT_I2C
|
||||
|
@ -4070,6 +4174,12 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
|
|||
}
|
||||
#endif // USE_I2S_AUDIO
|
||||
#endif // ESP32
|
||||
if (!strncmp_XP(lp, XPSTR("i("), 2)) {
|
||||
// convert to integer var
|
||||
lp = GetNumericArgument(lp + 2, OPER_EQU, &fvar, gv);
|
||||
*(uint32_t*)&fvar = fvar;
|
||||
goto nfuncexit;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef ESP32
|
||||
|
@ -4144,6 +4254,21 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
|
|||
goto nfuncexit;
|
||||
}
|
||||
#endif // USE_LVGL
|
||||
|
||||
#ifdef USE_UFILESYS
|
||||
#ifdef USE_SCRIPT_FATFS_EXT
|
||||
if (!strncmp_XP(lp, XPSTR("lfw("), 4)) {
|
||||
char path[SCRIPT_MAXSSIZE];
|
||||
lp = GetStringArgument(lp + 4, OPER_EQU, path, 0);
|
||||
char payload[SCRIPT_MAXSSIZE];
|
||||
lp = GetStringArgument(lp, OPER_EQU, payload, 0);
|
||||
lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0);
|
||||
// write to logfile
|
||||
fvar = script_logfile_write(path, payload, fvar);
|
||||
goto nfuncexit;
|
||||
}
|
||||
#endif // USE_SCRIPT_FATFS_EXT
|
||||
#endif
|
||||
break;
|
||||
case 'm':
|
||||
if (!strncmp_XP(lp, XPSTR("med("), 4)) {
|
||||
|
@ -4293,6 +4418,21 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
|
|||
}
|
||||
break;
|
||||
|
||||
#ifdef USE_SCRIPT_ONEWIRE
|
||||
case 'o':
|
||||
if (!strncmp_XP(vname, XPSTR("ow("), 3)) {
|
||||
lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, 0);
|
||||
uint8_t sel = fvar;
|
||||
SCRIPT_SKIP_SPACES
|
||||
if (*lp != ')') {
|
||||
lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0);
|
||||
}
|
||||
fvar = script_ow(sel, fvar);
|
||||
goto nfuncexit;
|
||||
}
|
||||
break;
|
||||
#endif // USE_SCRIPT_ONEWIRE
|
||||
|
||||
case 'p':
|
||||
if (!strncmp_XP(lp, XPSTR("pin["), 4)) {
|
||||
// raw pin level
|
||||
|
@ -4610,9 +4750,15 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
|
|||
lp++;
|
||||
}
|
||||
}
|
||||
bool isint = is_int_var(lp);
|
||||
lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv);
|
||||
char str[SCRIPT_MAXSSIZE];
|
||||
f2char(fvar, dprec, lzero, str, dsep);
|
||||
if (isint) {
|
||||
double dvar = *(int32_t*)&fvar;
|
||||
f2char(dvar, dprec, lzero, str, dsep);
|
||||
} else {
|
||||
f2char(fvar, dprec, lzero, str, dsep);
|
||||
}
|
||||
if (sp) strlcpy(sp, str, glob_script_mem.max_ssize);
|
||||
lp++;
|
||||
len = 0;
|
||||
|
@ -5174,6 +5320,14 @@ extern char *SML_GetSVal(uint32_t index);
|
|||
|
||||
#endif //USE_SCRIPT_SERIAL
|
||||
|
||||
if (!strncmp_XP(lp, XPSTR("sas("), 4)) {
|
||||
lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0);
|
||||
if (fvar < 1 || fvar > 3) {
|
||||
fvar = 1;
|
||||
}
|
||||
script_sort_string_array(fvar - 1);
|
||||
goto nfuncexit;
|
||||
}
|
||||
|
||||
#ifdef USE_SCRIPT_SPI
|
||||
if (!strncmp_XP(lp, XPSTR("spi("), 4)) {
|
||||
|
@ -5789,6 +5943,43 @@ char *getop(char *lp, uint8_t *operand) {
|
|||
return lp;
|
||||
}
|
||||
|
||||
#ifdef USE_SCRIPT_FATFS_EXT
|
||||
#ifdef USE_UFILESYS
|
||||
int32_t script_logfile_write(char *path, char *payload, uint32_t size) {
|
||||
|
||||
File rfd = ufsp->open(path, FS_FILE_APPEND);
|
||||
if (rfd == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t fsize = rfd.size();
|
||||
// append string
|
||||
rfd.write((uint8_t*)payload, strlen(payload));
|
||||
rfd.write((uint8_t*)"\n", 1);
|
||||
if (fsize < size) {
|
||||
rfd.close();
|
||||
return fsize;
|
||||
}
|
||||
rfd.seek(0, SeekSet);
|
||||
String line = rfd.readStringUntil('\n');
|
||||
File wfd = ufsp->open("/ltmp", FS_FILE_WRITE);
|
||||
if (!wfd) {
|
||||
return -2;
|
||||
}
|
||||
while (rfd.available()) {
|
||||
line = rfd.readStringUntil('\n');
|
||||
wfd.write((uint8_t*)line.c_str(), line.length());
|
||||
wfd.write((uint8_t*)"\n", 1);
|
||||
}
|
||||
rfd.close();
|
||||
wfd.close();
|
||||
ufsp->remove(path);
|
||||
ufsp->rename("/ltmp", path);
|
||||
|
||||
return fsize;
|
||||
}
|
||||
#endif // USE_UFILESYS
|
||||
#endif // USE_SCRIPT_FATFS_EXT
|
||||
|
||||
#ifdef ESP8266
|
||||
extern "C" {
|
||||
|
@ -6090,6 +6281,24 @@ extern "C" {
|
|||
|
||||
#endif // USE_HOMEKIT
|
||||
|
||||
|
||||
bool is_int_var(char *name) {
|
||||
uint8_t vtype;
|
||||
struct T_INDEX ind;
|
||||
|
||||
isvar(name, &vtype, &ind, 0, 0, 0);
|
||||
|
||||
if (vtype != VAR_NV) {
|
||||
if (vtype == NUM_RES || (vtype & STYPE) == 0) {
|
||||
// numeric result
|
||||
if (ind.bits.integer) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// replace vars in cmd %var%
|
||||
void Replace_Cmd_Vars(char *srcbuf, uint32_t srcsize, char *dstbuf, uint32_t dstsize) {
|
||||
char *cp;
|
||||
|
@ -6148,7 +6357,8 @@ void Replace_Cmd_Vars(char *srcbuf, uint32_t srcsize, char *dstbuf, uint32_t dst
|
|||
if (vtype == NUM_RES || (vtype & STYPE) == 0) {
|
||||
// numeric result
|
||||
if (ind.bits.integer) {
|
||||
dtostrfd(*(int32_t*)&fvar, 0, string);
|
||||
double dval = *(int32_t*)&fvar;
|
||||
f2char(dval, dprec, lzero, string, dsep);
|
||||
} else {
|
||||
f2char(fvar, dprec, lzero, string, dsep);
|
||||
}
|
||||
|
@ -7147,6 +7357,7 @@ getnext:
|
|||
} else {
|
||||
dfvar = &glob_script_mem.fvars[index];
|
||||
sysv_type = 0;
|
||||
glob_script_mem.res_ivar = ind.bits.integer;
|
||||
}
|
||||
numeric = 1;
|
||||
SCRIPT_SKIP_SPACES
|
||||
|
@ -7483,6 +7694,201 @@ getnext:
|
|||
return -1;
|
||||
}
|
||||
|
||||
#ifdef USE_SCRIPT_ONEWIRE
|
||||
|
||||
uint32_t script_ow(uint8_t sel, uint32_t val) {
|
||||
uint32_t res = 0;
|
||||
uint8_t bits;
|
||||
bool invert = false;
|
||||
ScriptOneWire *ow = &glob_script_mem.ow;
|
||||
|
||||
if (sel >= 10 && sel <= 18) {
|
||||
if (val < 1 || val > MAX_DS_SENSORS) {
|
||||
val = 1;
|
||||
}
|
||||
return ow->ds_address[val - 1][sel - 10];
|
||||
}
|
||||
|
||||
if (sel > 0 && (ow->ds == nullptr && ow->dsh == nullptr)) {
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
switch (sel) {
|
||||
case 0:
|
||||
if (val & 0x8000) {
|
||||
if (val & 0x10000) {
|
||||
// inverted serial
|
||||
invert = true;
|
||||
}
|
||||
val &= 0x7fff;
|
||||
ow->ts = new TasmotaSerial(val & 0xff, (val >> 8) & 0x7f, 1, 0, 64);
|
||||
if (ow->ts) {
|
||||
|
||||
ow->ts->begin(9600);
|
||||
|
||||
#ifdef ESP8266
|
||||
if (ow->ts->hardwareSerial()) {
|
||||
ClaimSerial();
|
||||
#ifdef ALLOW_OW_INVERT
|
||||
if (invert == true) {
|
||||
U0C0 = U0C0 | BIT(UCRXI) | BIT(UCTXI); // Inverse RX, TX
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // ESP8266
|
||||
|
||||
#ifdef ESP32
|
||||
#ifdef ALLOW_OW_INVERT
|
||||
if (invert == true) {
|
||||
HardwareSerial *hws = ow->ts->getesp32hws();
|
||||
hws->end();
|
||||
hws->begin(9600, SERIAL_8N1, val & 0xff, (val >> 8) & 0x7f, true);
|
||||
}
|
||||
#endif
|
||||
#endif // ESP32
|
||||
|
||||
ow->dsh = new DS2480B(ow->ts);
|
||||
ow->dsh->begin();
|
||||
}
|
||||
ow->ds = nullptr;
|
||||
} else {
|
||||
ow->ds = new OneWire(val);
|
||||
ow->dsh = nullptr;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (ow->ds) {
|
||||
ow->ds->reset();
|
||||
} else {
|
||||
ow->dsh->reset();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (ow->ds) {
|
||||
ow->ds->skip();
|
||||
} else {
|
||||
ow->dsh->skip();
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (ow->ds) {
|
||||
ow->ds->write(val, 1);
|
||||
} else {
|
||||
ow->dsh->write(val, 1);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (ow->ds) {
|
||||
return ow->ds->read();
|
||||
} else {
|
||||
return ow->dsh->read();
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (ow->ds) {
|
||||
ow->ds->reset_search();
|
||||
} else {
|
||||
ow->dsh->reset_search();
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (val < 1 || val > MAX_DS_SENSORS) {
|
||||
val = 1;
|
||||
}
|
||||
if (ow->ds) {
|
||||
return ow->ds->search(ow->ds_address[val - 1]);
|
||||
} else {
|
||||
return ow->dsh->search(ow->ds_address[val - 1]);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (val < 1 || val > MAX_DS_SENSORS) {
|
||||
val = 1;
|
||||
}
|
||||
if (ow->ds) {
|
||||
ow->ds->select(ow->ds_address[val - 1]);
|
||||
} else {
|
||||
ow->dsh->select(ow->ds_address[val - 1]);
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
bits = val & 0xc0;
|
||||
val &= 0x3f;
|
||||
if (val < 1 || val > MAX_DS_SENSORS) {
|
||||
val = 1;
|
||||
}
|
||||
if (ow->ds) {
|
||||
ow->ds->reset();
|
||||
ow->ds->select(ow->ds_address[val - 1]);
|
||||
ow->ds->write(0xf5, 1);
|
||||
ow->ds->write(0x0c, 1);
|
||||
ow->ds->write(0xff, 1);
|
||||
res = ow->ds->read();
|
||||
ow->ds->write(bits, 1);
|
||||
} else {
|
||||
ow->dsh->reset();
|
||||
ow->dsh->select(ow->ds_address[val - 1]);
|
||||
ow->dsh->write(0xf5, 1);
|
||||
ow->dsh->write(0x0c, 1);
|
||||
ow->dsh->write(0xff, 1);
|
||||
res = ow->dsh->read();
|
||||
ow->dsh->write(bits, 1);
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
bits = val & 0x80;
|
||||
val &= 0x3f;
|
||||
if (val < 1 || val > MAX_DS_SENSORS) {
|
||||
val = 1;
|
||||
}
|
||||
|
||||
if (ow->ds) {
|
||||
ow->ds->reset();
|
||||
ow->ds->select(ow->ds_address[val - 1]);
|
||||
if (!bits) {
|
||||
ow->ds->write(0x44, 1);
|
||||
} else {
|
||||
ow->ds->write(0xbe, 1);
|
||||
delay(10);
|
||||
res = ow->ds->read();
|
||||
res |= ow->ds->read() << 8;
|
||||
ow->ds->reset();
|
||||
}
|
||||
} else {
|
||||
ow->dsh->reset();
|
||||
ow->dsh->select(ow->ds_address[val - 1]);
|
||||
if (!bits) {
|
||||
ow->dsh->write(0x44, 1);
|
||||
} else {
|
||||
ow->dsh->write(0xbe, 1);
|
||||
delay(10);
|
||||
res = ow->dsh->read();
|
||||
res |= ow->dsh->read() << 8;
|
||||
ow->dsh->reset();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 99:
|
||||
if (ow->ds) {
|
||||
ow->ds->reset();
|
||||
delete ow->ds;
|
||||
ow->ds = nullptr;
|
||||
} else {
|
||||
ow->dsh->reset();
|
||||
delete ow->dsh;
|
||||
ow->dsh = nullptr;
|
||||
delete ow->ts;
|
||||
}
|
||||
break;
|
||||
case 98:
|
||||
ow->ts->write(val);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif // USE_SCRIPT_ONEWIRE
|
||||
|
||||
|
||||
|
||||
#ifdef USE_SCRIPT_SPI
|
||||
// transfer 1-3 bytes
|
||||
|
@ -7586,6 +7992,25 @@ bool Script_Close_Serial() {
|
|||
}
|
||||
#endif //USE_SCRIPT_SERIAL
|
||||
|
||||
|
||||
void script_sort_array(float *array, uint16_t size) {
|
||||
bool swapped;
|
||||
do {
|
||||
swapped = false;
|
||||
for (uint16_t i = 0; i < size - 1; ++i) {
|
||||
if (array[i] > array[i + 1]) {
|
||||
// swap
|
||||
float tmp = array[i];
|
||||
array[i] = array[i + 1];
|
||||
array[i + 1] = tmp;
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
size -= 1;
|
||||
} while (swapped);
|
||||
}
|
||||
|
||||
|
||||
bool Is_gpio_used(uint8_t gpiopin) {
|
||||
if (gpiopin >= 0 && (gpiopin < nitems(TasmotaGlobal.gpio_pin)) && (TasmotaGlobal.gpio_pin[gpiopin] > 0)) {
|
||||
return true;
|
||||
|
@ -9673,6 +10098,11 @@ void Script_Check_HTML_Setvars(void) {
|
|||
*cp1 = '=';
|
||||
cp1++;
|
||||
|
||||
if (is_int_var(vname)) {
|
||||
memmove(cp1 + 1, cp1, strlen(cp1));
|
||||
*cp1++ = '#';
|
||||
}
|
||||
|
||||
struct T_INDEX ind;
|
||||
uint8_t vtype;
|
||||
isvar(vname, &vtype, &ind, 0, 0, 0);
|
||||
|
@ -10143,7 +10573,7 @@ const char *gc_str;
|
|||
lp = GetStringArgument(lp, OPER_EQU, right, 0);
|
||||
SCRIPT_SKIP_SPACES
|
||||
|
||||
WSContentSend_P(SCRIPT_MSG_SLIDER, left,mid, right, (uint32_t)min, (uint32_t)max, (uint32_t)val, vname);
|
||||
WSContentSend_P(SCRIPT_MSG_SLIDER, left, mid, right, (uint32_t)min, (uint32_t)max, (uint32_t)val, vname);
|
||||
lp++;
|
||||
|
||||
} else if (!strncmp(lin, "ck(", 3)) {
|
||||
|
@ -10400,6 +10830,8 @@ const char *gc_str;
|
|||
char vname[16];
|
||||
ScriptGetVarname(vname, slp, sizeof(vname));
|
||||
|
||||
bool isint = is_int_var(vname);
|
||||
|
||||
char label[SCRIPT_MAXSSIZE];
|
||||
lp = GetStringArgument(lp, OPER_EQU, label, 0);
|
||||
SCRIPT_SKIP_SPACES
|
||||
|
@ -10417,10 +10849,17 @@ const char *gc_str;
|
|||
}
|
||||
|
||||
char vstr[16],minstr[16],maxstr[16],stepstr[16];
|
||||
dtostrfd(val, dprec, vstr);
|
||||
dtostrfd(min, dprec, minstr);
|
||||
dtostrfd(max, dprec, maxstr);
|
||||
dtostrfd(step, dprec, stepstr);
|
||||
if (isint) {
|
||||
dtostrfd(*(int32_t*)&val, 0, vstr);
|
||||
dtostrfd(*(int32_t*)&min, dprec, minstr);
|
||||
dtostrfd(*(int32_t*)&max, dprec, maxstr);
|
||||
dtostrfd(*(int32_t*)&step, dprec, stepstr);
|
||||
} else {
|
||||
dtostrfd(val, dprec, vstr);
|
||||
dtostrfd(min, dprec, minstr);
|
||||
dtostrfd(max, dprec, maxstr);
|
||||
dtostrfd(step, dprec, stepstr);
|
||||
}
|
||||
WCS_DIV(specopt);
|
||||
WSContentSend_P(SCRIPT_MSG_NUMINP, center, label, minstr, maxstr, stepstr, vstr, tsiz, vname);
|
||||
WCS_DIV(specopt | WSO_STOP_DIV);
|
||||
|
@ -10867,8 +11306,11 @@ exgc:
|
|||
WSContentSend_P(PSTR("%s"), lin);
|
||||
}
|
||||
#else
|
||||
if (!(specopt&WSO_FORCEMAIN)) {
|
||||
lin++;
|
||||
|
||||
if (mc != 'z') {
|
||||
if (!(specopt&WSO_FORCEMAIN)) {
|
||||
lin++;
|
||||
}
|
||||
}
|
||||
WSContentSend_P(PSTR("%s"), lin);
|
||||
} else {
|
||||
|
@ -11305,10 +11747,27 @@ int32_t call2pwl(const char *url) {
|
|||
result.replace("instant", "i");
|
||||
result.replace("apparent", "a");
|
||||
result.replace("reactive", "r");
|
||||
|
||||
// custom replace
|
||||
#ifdef TESLA_POWERWALL_CTS1
|
||||
result.replace(TESLA_POWERWALL_CTS1, "PW_CTS1");
|
||||
#endif
|
||||
|
||||
#ifdef TESLA_POWERWALL_CTS2
|
||||
result.replace(TESLA_POWERWALL_CTS2, "PW_CTS2");
|
||||
#endif
|
||||
|
||||
if (result.length()>4095) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("PWL: result overflow: %d"), result.length());
|
||||
}
|
||||
|
||||
|
||||
#ifdef MQTT_DATA_STRING
|
||||
TasmotaGlobal.mqtt_data = result;
|
||||
#else
|
||||
strncpy(TasmotaGlobal.mqtt_data, result.c_str(), MESSZ);
|
||||
#endif
|
||||
|
||||
// meter aggregates has also too many tokens
|
||||
char *cp = (char*)result.c_str();
|
||||
if (!strncmp_P(cp, PSTR("{\"site\""), 7)) {
|
||||
|
@ -11415,36 +11874,38 @@ void cpy2lf(char *dst, uint32_t dstlen, char *src) {
|
|||
}
|
||||
|
||||
#ifdef USE_SCRIPT_I2C
|
||||
uint8_t script_i2c_addr;
|
||||
TwoWire *script_i2c_wire;
|
||||
uint32_t script_i2c(uint8_t sel, uint16_t val, uint32_t val1) {
|
||||
uint32_t rval = 0;
|
||||
uint8_t bytes = 1;
|
||||
|
||||
if (sel > 0) {
|
||||
if (!glob_script_mem.script_i2c_wire) return 0;
|
||||
}
|
||||
|
||||
switch (sel) {
|
||||
case 0:
|
||||
script_i2c_addr = val;
|
||||
glob_script_mem.script_i2c_addr = val;
|
||||
#ifdef ESP32
|
||||
if (val1 == 0) script_i2c_wire = &Wire;
|
||||
else script_i2c_wire = &Wire1;
|
||||
if (val1 == 0) glob_script_mem.script_i2c_wire = &Wire;
|
||||
else glob_script_mem.script_i2c_wire = &Wire1;
|
||||
#else
|
||||
script_i2c_wire = &Wire;
|
||||
glob_script_mem.script_i2c_wire = &Wire;
|
||||
#endif
|
||||
script_i2c_wire->beginTransmission(script_i2c_addr);
|
||||
return (0 == script_i2c_wire->endTransmission());
|
||||
glob_script_mem.script_i2c_wire->beginTransmission(glob_script_mem.script_i2c_addr);
|
||||
return (0 == glob_script_mem.script_i2c_wire->endTransmission());
|
||||
break;
|
||||
case 2:
|
||||
// read 1..4 bytes
|
||||
if ((val & 0x8000) == 0) {
|
||||
script_i2c_wire->beginTransmission(script_i2c_addr);
|
||||
script_i2c_wire->write(val);
|
||||
script_i2c_wire->endTransmission();
|
||||
glob_script_mem.script_i2c_wire->beginTransmission(glob_script_mem.script_i2c_addr);
|
||||
glob_script_mem.script_i2c_wire->write(val);
|
||||
glob_script_mem.script_i2c_wire->endTransmission();
|
||||
}
|
||||
script_i2c_wire->requestFrom((int)script_i2c_addr, (int)val1);
|
||||
glob_script_mem.script_i2c_wire->requestFrom((int)glob_script_mem.script_i2c_addr, (int)val1);
|
||||
|
||||
for (uint8_t cnt = 0; cnt < val1; cnt++) {
|
||||
rval <<= 8;
|
||||
rval |= (uint8_t)script_i2c_wire->read();
|
||||
rval |= (uint8_t)glob_script_mem.script_i2c_wire->read();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -11454,23 +11915,23 @@ uint32_t script_i2c(uint8_t sel, uint16_t val, uint32_t val1) {
|
|||
case 13:
|
||||
// write 1 .. 4 bytes
|
||||
bytes = sel - 9;
|
||||
script_i2c_wire->beginTransmission(script_i2c_addr);
|
||||
glob_script_mem.script_i2c_wire->beginTransmission(glob_script_mem.script_i2c_addr);
|
||||
if ((val & 0x8000) == 0) {
|
||||
script_i2c_wire->write(val);
|
||||
glob_script_mem.script_i2c_wire->write(val);
|
||||
}
|
||||
if ((val & 0x4000) == 0) {
|
||||
for (uint8_t cnt = 0; cnt < bytes; cnt++) {
|
||||
script_i2c_wire->write(val1);
|
||||
glob_script_mem.script_i2c_wire->write(val1);
|
||||
val1 >>= 8;
|
||||
}
|
||||
} else {
|
||||
uint32_t wval = 0;
|
||||
for (uint8_t cnt = 0; cnt < bytes; cnt++) {
|
||||
wval = val1 >> ((bytes - 1 - cnt) * 8);
|
||||
script_i2c_wire->write(wval);
|
||||
glob_script_mem.script_i2c_wire->write(wval);
|
||||
}
|
||||
}
|
||||
script_i2c_wire->endTransmission();
|
||||
glob_script_mem.script_i2c_wire->endTransmission();
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -11918,6 +12379,9 @@ bool Xdrv10(uint32_t function)
|
|||
case FUNC_INIT:
|
||||
|
||||
//bitWrite(Settings->rule_enabled, 0, 0); // >>>>>>>>>>>
|
||||
#ifndef NO_SCRIPT_STOP_ON_ERROR
|
||||
bitWrite(Settings->rule_stop, 0, 1);
|
||||
#endif
|
||||
|
||||
// set defaults to rules memory
|
||||
//bitWrite(Settings->rule_enabled,0,0);
|
||||
|
@ -12224,6 +12688,10 @@ bool Xdrv10(uint32_t function)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case FUNC_BUTTON_MULTI_PRESSED:
|
||||
if (bitRead(Settings->rule_enabled, 0)) {
|
||||
Run_Scripter1(">b", 2, 0);
|
||||
}
|
||||
#endif //USE_BUTTON_EVENT
|
||||
|
||||
case FUNC_LOOP:
|
||||
|
|
Loading…
Reference in New Issue