18 Commits

Author SHA1 Message Date
Климов Андрей Николаевич
eb68556012 STM32 persistent MVP, cross-compiled & binaries 2023-05-06 02:53:01 +03:00
Климов Андрей Николаевич
30f7b36a9c Multi-AC 2023-04-10 19:19:45 +03:00
Климов Андрей Николаевич
927272824c counter fix 2023-04-10 00:01:20 +03:00
Климов Андрей Николаевич
bab472d2d1 JSON RAM optimization (update libs needed), HTTP 2023-04-09 21:37:37 +03:00
Климов Андрей Николаевич
ec306c4934 Cumulative changes/pre-release 2023-04-02 17:27:02 +03:00
Климов Андрей Николаевич
3e0566cf07 ENABLE & DISABLE to separate topic and XON timer 2023-01-30 01:10:34 +03:00
Климов Андрей Николаевич
86d0d784a0 Mercury electricity counter driver, refactoring 2023-01-29 12:33:22 +03:00
Климов Андрей Николаевич
b06dad9395 noSerial option, DHT fix, 8266 slim to fit Sonoff 2022-12-16 17:14:59 +03:00
a974290389 Complex MBUS mapping, PID fix 2022-12-04 03:19:07 +03:00
2da04b45bf PID fixes/improvements and MBUS improvements 2022-11-28 14:57:43 +03:00
724eabc22f API CORS = * 2022-11-24 02:00:20 +03:00
c70a4eaac9 bin flash update fix (after revorking) & bins 2022-11-22 01:01:47 +03:00
a956b6f8e2 RAM optim to save huge configs to flash, PID min/max 2022-11-19 23:30:02 +03:00
07688f53ae core fixes (int & tens val<1), mbus optimization 2022-11-05 16:40:31 +03:00
6d28cb9f34 null mapping fix 2022-11-01 01:48:01 +03:00
d7e93177d6 possibility to turn val mapping off ("val":null) 2022-11-01 00:49:54 +03:00
c23543b213 PID & Modbus fine tuning 2022-10-31 23:56:51 +03:00
b94ab723ee modbus negative register fix 2022-10-13 08:22:06 +03:00
110 changed files with 61985 additions and 47088 deletions

View File

@@ -3,4 +3,5 @@
-DWiz5100
#-DPID_DISABLE
-DRESTART_LAN_ON_MQTT_ERRORS
-D CORS=\"http://lazyhome.ru\"
-D CORS=\"*\"
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"

View File

@@ -1,7 +1,7 @@
#-DW5500_CS_PIN=53
-DDMX_SMOOTH
-DSYSLOG_ENABLE
#-DMODBUS_DIMMER_PARAM=SERIAL_8E1
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
-DARTNET_ENABLE
-DOTA
-DSTATUSLED
@@ -10,7 +10,8 @@
-DARDUINO_OTA_MDNS_DISABLE
-DMDNS_ENABLE
-DMCP23017
-DCORS=\"http://lazyhome.ru\"
-D CORS=\"*\"
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"
-DTIMER_INT
-DRESTART_LAN_ON_MQTT_ERRORS

View File

@@ -26,6 +26,10 @@
#-DmodbusSerial=Serial1
#-DMODBUS_DEBUG
#-DMODBUS_UART_RX_PIN=16
#-DMODBUS_UART_TX_PIN=17
#-DmodbusSerial=Serial2
# Use default pins for modbus UART
#-DMODBUS_UART_RX_PIN=-1
#-DMODBUS_UART_TX_PIN=-1
@@ -46,5 +50,10 @@
-DFS_PREPARE
-DRESTART_LAN_ON_MQTT_ERRORS
-D CORS=\"http://lazyhome.ru\"
-DOTA_PORT=80
#-D CORS=\"http://lazyhome.ru\"
-DOTA_PORT=80
-DMQTT_KEEPALIVE=10
-DMQTT_SOCKET_TIMEOUT=20
-D CORS=\"*\"
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"

View File

@@ -17,7 +17,8 @@
-DFS_PREPARE
-DRESTART_LAN_ON_MQTT_ERRORS
#-D CORS=\"http://lazyhome.ru\"
-D CORS=\"*\"
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"
-DOTA_PORT=80
#oct22 - violation in Publish/OnMQTTConnect while publish homie info

View File

@@ -12,8 +12,8 @@
-DTIMER_INT
#-DFLASH_OFFSET=-256
# Serial parameters for LEGACY Modbus
-DMODBUS_DIMMER_PARAM=SERIAL_8E1
# default MODBUS Serial parameters for LEGACY Modbus and MODBUS over IP
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
#Set Logariphmic law for DMX channels bright
-DBRIGHT_LOG
@@ -34,5 +34,9 @@
#-DdebugSerialPort=Serial
-DRESTART_LAN_ON_MQTT_ERRORS
-D CORS=\"http://lazyhome.ru\"
-DOTA_PORT=80
#-D CORS=\"http://lazyhome.ru\"
-DOTA_PORT=80
-D CORS=\"*\"
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"
#-D MERCURY_ENABLE
#-D IPMODBUS

View File

@@ -19,5 +19,6 @@
-DOTA
-DRESTART_LAN_ON_MQTT_ERRORS
-D CORS=\"http://lazyhome.ru\"
-D CORS=\"*\"
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"
-DOTA_PORT=80

View File

@@ -1,4 +1,4 @@
#-DMODBUS_DIMMER_PARAM=SERIAL_8E1
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
-DAVR_DMXOUT_PIN=18
-DSYSLOG_ENABLE
-DWiz5100
@@ -7,5 +7,6 @@
-DMDNS_ENABLE
-DRESTART_LAN_ON_MQTT_ERRORS
-D CORS=\"http://lazyhome.ru\"
-DOTA_PORT=80
-D CORS=\"*\"
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"
-DOTA_PORT=80

View File

@@ -1,5 +1,5 @@
-DWiz5500
#-DMODBUS_DIMMER_PARAM=SERIAL_8E1
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
-DAVR_DMXOUT_PIN=18
-DSYSLOG_ENABLE
#-DPID_DISABLE
@@ -7,5 +7,6 @@
-DMDNS_ENABLE
-DRESTART_LAN_ON_MQTT_ERRORS
-D CORS=\"http://lazyhome.ru\"
-DOTA_PORT=80
-D CORS=\"*\"
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"
-DOTA_PORT=80

View File

@@ -1,5 +1,5 @@
#-DMODBUS_DIMMER_PARAM=SERIAL_8E1
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
#-DAVR_DMXOUT_PIN=18
-DDMX_DISABLE
-DMODBUS_DISABLE
@@ -17,10 +17,11 @@
-DMOTOR_DISABLE
#-DWiz5100
-DARDUINO_OTA_MDNS_DISABLE
#-DMDNS_ENABLE
-DMDNS_ENABLE
-DRESTART_LAN_ON_MQTT_ERRORS
-D CORS=\"http://lazyhome.ru\"
-D CORS=\"*\"
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"
# Example of UARTBRIDGE configuration
#-DUARTBRIDGE_ENABLE

View File

@@ -1,9 +1,9 @@
#-DMODBUS_DIMMER_PARAM=SERIAL_8E1
#-DMODBUS_SERIAL_PARAM=SERIAL_8E1
#-DAVR_DMXOUT_PIN=18
-DDMX_DISABLE
-DMODBUS_DISABLE
#-DMBUS_DISABLE
-DMBUS_DISABLE
#-DOWIRE_DISABLE
-DDHT_DISABLE
-DCOUNTER_DISABLE
@@ -19,7 +19,8 @@
-DARDUINO_OTA_MDNS_DISABLE
#-DMDNS_ENABLE
-DRESTART_LAN_ON_MQTT_ERRORS
-D CORS=\"http://lazyhome.ru\"
-D CORS=\"*\"
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"
-DOTA_PORT=80
-DHSV_DISABLE
-DMULTIVENT_DISABLE

View File

@@ -14,3 +14,5 @@
-DPID_DISABLE
#-DMCP23017
-D CORS=\"*\"
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"

View File

@@ -9,15 +9,31 @@
-DSPILED_DISABLE
-DAC_DISABLE
-DPID_DISABLE
-DdebugSerialPort=SerialUSB
-DSerialPortType=USBSerial
-DSERIAL_BAUD=0
-DPIO_FRAMEWORK_ARDUINO_ENABLE_CDC
-DUSBCON
-DENABLE_HWSERIAL1
-DdebugSerialPort=Serial1
#-DFLASH_BASE_ADDRESS
#-DFLASH_DATA_SECTOR
#-DFLASH_PAGE_NUMBER
-D PIO_FRAMEWORK_ARDUINO_ENABLE_MASS_STORAGE
-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC_AND_MSC
#-DdebugSerialPort=SerialUSB
#-DSerialPortType=USBSerial
#-DSERIAL_BAUD=0
#-DPIO_FRAMEWORK_ARDUINO_ENABLE_CDC
#-DUSBCON
#-DUSBD_VID=0x0483
#-DUSBD_PID=0x5740
#-DUSB_MANUFACTURER="Unknown"
#-DUSB_PRODUCT="\"BLUEPILL_F103C8\""
#-DHAL_PCD_MODULE_ENABLED
#-D USBD_USE_CDC
-D HAL_CAN_MODULE_ENABLED
#HAL_ETH_MODULE_DISABLED
#HAL_SD_MODULE_DISABLED
#HAL_DAC_MODULE_DISABLED

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
..\tools\win\tool-avrdude\avrdude -C ../tools/mac/tool-avrdude/avrdude.conf -v -V -P com8 -patmega2560 -cwiring -b115200 -D -Uflash:w:firmware.hex:i

View File

@@ -0,0 +1 @@
..\tools\arduinoOTA.exe -address 192.168.11.213 -port 80 -username arduino -password password -sketch firmware.bin -b -upload /sketch

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
arduinoOTA -address 192.168.88.54 -port 80 -username arduino -password password -b -upload /sketch -sketch firmware.bin

Binary file not shown.

View File

@@ -0,0 +1,91 @@
@ECHO off
REM Wait X second for memory on Arduino Due is erased.
SET WAIT_ERASED=4
ECHO ------ External tool BossacArduinoDue started ------
REM number of command line arguments ok?
REM IF [%1]==[] GOTO error_args
REM IF [%2]==[] GOTO error_args
REM set command line arguments
SET BOSSACPATH=..\tools\win\tool-bossac\bossac.exe
SET BINFILE=firmware.bin
REM parse command line arguments
SET BOSSACPATH=%BOSSACPATH:"=%
SET BINFILE=%BINFILE:"=%
REM workeround for bug in Atmel Studio 6.0.1996 Service Pack 2
SET BINFILE=%BINFILE:\\=\%
SET BINFILE=%BINFILE:.cproj=%
REM bossac path exist?
IF NOT EXIST "%BOSSACPATH%" GOTO error_arg1
REM bin file exist?
IF NOT EXIST "%BINFILE%" GOTO error_binfile
REM fetch DeviceID of Arduino Due Programming Port from WMI Service
FOR /f "tokens=* skip=1" %%a IN ('wmic PATH Win32_SerialPort Where "Caption LIKE '%%BOSSA%%'" get DeviceID') DO (
SET COMX=%%a
GOTO exit1
)
REM Arduino Due Programming Port not exist
GOTO error_comport
:exit1
REM remove blank
SET COMPORT=%COMX: =%
REM report in Atmel Studio 6.0 IDE output window
ECHO BossacPath=%BOSSACPATH%
ECHO BinFile=%BINFILE%
ECHO Arduino Due Programming Port is detected as %COMPORT%.
REM The bossac bootloader only runs if the memory on Arduino Due is erased.
REM The Arduino IDE does this by opening and closing the COM port at 1200 baud.
REM This causes the Due to execute a soft erase command.
ECHO Forcing reset using 1200bps open/close on port
ECHO MODE %COMPORT%:1200,N,8,1
MODE %COMPORT%:1200,N,8,1
REM Wait X second for memory on Arduino Due is erased.
ECHO Wait for memory on Arduino Due is erased...
PING -n %WAIT_ERASED% 127.0.0.1>NUL
REM Execute bossac.exe
ECHO Execute bossac with command line:
"%BOSSACPATH%" -i --port=%COMPORT% --unlock -R
REM START /WAIT "" "%BOSSACPATH%" -i --port=%COMPORT% -u -e -w -v -b "%BINFILE%" -R
GOTO end
:error_args
ECHO Error: wrong number of command line arguments passed!
GOTO end
:error_arg1
ECHO Error: command line argument 1 - path to bossac.exe not exist! - "C:\Program Files (x86)\arduino-1.5.2\hardware\tools\bossac.exe"
ECHO Error: command line argument 1 - argument passed = %1
GOTO end
:error_arg2
ECHO Error: command line argument 2 - path to bin file not exist! - use $(OutputDirectory)\$(OutputFileName).bin
ECHO Error: command line argument 2 - argument passed = %1
GOTO end
:error_binfile
ECHO Error: bin file "%BINFILE%" not exist!
GOTO end
:error_comport
ECHO Error: Arduino Due Programming Port not found!
:end
ECHO ======================== Done ========================

View File

@@ -59,8 +59,8 @@ PING -n %WAIT_ERASED% 127.0.0.1>NUL
REM Execute bossac.exe
ECHO Execute bossac with command line:
ECHO "%BOSSACPATH%" -i -d --port=%COMPORT% -U false -e -w -v -b "%BINFILE%" -R
START /WAIT "" "%BOSSACPATH%" -i --port=%COMPORT% -U false -e -w -v -b "%BINFILE%" -R
"%BOSSACPATH%" -i --port=%COMPORT% -U false -w -v -b "%BINFILE%" -R
REM START /WAIT "" "%BOSSACPATH%" -i --port=%COMPORT% -U false -e -w -v -b "%BINFILE%" -R
GOTO end

View File

@@ -0,0 +1,91 @@
@ECHO off
REM Wait X second for memory on Arduino Due is erased.
SET WAIT_ERASED=4
ECHO ------ External tool BossacArduinoDue started ------
REM number of command line arguments ok?
REM IF [%1]==[] GOTO error_args
REM IF [%2]==[] GOTO error_args
REM set command line arguments
SET BOSSACPATH=..\tools\win\tool-bossac\bossac.exe
SET BINFILE=firmware.bin
REM parse command line arguments
SET BOSSACPATH=%BOSSACPATH:"=%
SET BINFILE=%BINFILE:"=%
REM workeround for bug in Atmel Studio 6.0.1996 Service Pack 2
SET BINFILE=%BINFILE:\\=\%
SET BINFILE=%BINFILE:.cproj=%
REM bossac path exist?
IF NOT EXIST "%BOSSACPATH%" GOTO error_arg1
REM bin file exist?
IF NOT EXIST "%BINFILE%" GOTO error_binfile
REM fetch DeviceID of Arduino Due Programming Port from WMI Service
FOR /f "tokens=* skip=1" %%a IN ('wmic PATH Win32_SerialPort Where "Caption LIKE '%%BOSSA%%'" get DeviceID') DO (
SET COMX=%%a
GOTO exit1
)
REM Arduino Due Programming Port not exist
GOTO error_comport
:exit1
REM remove blank
SET COMPORT=%COMX: =%
REM report in Atmel Studio 6.0 IDE output window
ECHO BossacPath=%BOSSACPATH%
ECHO BinFile=%BINFILE%
ECHO Arduino Due Programming Port is detected as %COMPORT%.
REM The bossac bootloader only runs if the memory on Arduino Due is erased.
REM The Arduino IDE does this by opening and closing the COM port at 1200 baud.
REM This causes the Due to execute a soft erase command.
ECHO Forcing reset using 1200bps open/close on port
ECHO MODE %COMPORT%:1200,N,8,1
MODE %COMPORT%:1200,N,8,1
REM Wait X second for memory on Arduino Due is erased.
ECHO Wait for memory on Arduino Due is erased...
PING -n %WAIT_ERASED% 127.0.0.1>NUL
REM Execute bossac.exe
ECHO Execute bossac with command line:
"%BOSSACPATH%" -i --port=%COMPORT% -w -v -b "%BINFILE%" -R
REM START /WAIT "" "%BOSSACPATH%" -i --port=%COMPORT% -u -e -w -v -b "%BINFILE%" -R
GOTO end
:error_args
ECHO Error: wrong number of command line arguments passed!
GOTO end
:error_arg1
ECHO Error: command line argument 1 - path to bossac.exe not exist! - "C:\Program Files (x86)\arduino-1.5.2\hardware\tools\bossac.exe"
ECHO Error: command line argument 1 - argument passed = %1
GOTO end
:error_arg2
ECHO Error: command line argument 2 - path to bin file not exist! - use $(OutputDirectory)\$(OutputFileName).bin
ECHO Error: command line argument 2 - argument passed = %1
GOTO end
:error_binfile
ECHO Error: bin file "%BINFILE%" not exist!
GOTO end
:error_comport
ECHO Error: Arduino Due Programming Port not found!
:end
ECHO ======================== Done ========================

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
cp ../../.pio/build/lighthub21/firmware.bin .

6597
compiled/nrf52840-5500 Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
compiled/tools/arduinoOTA Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

16
compiled/update_bin.bat Normal file
View File

@@ -0,0 +1,16 @@
copy ..\.pio\build\due\firmware.bin due
copy ..\.pio\build\controllino\firmware.hex controllino
copy ..\.pio\build\m5stack\firmware.bin m5stack
copy ..\.pio\build\mega2560slim-5100\firmware.hex mega2560slim-5100
copy ..\.pio\build\mega2560slim-5100\firmware.bin mega2560slim-5100
copy ..\.pio\build\mega2560slim2\firmware.hex mega2560slim2
copy ..\.pio\build\mega2560slim2\firmware.bin mega2560slim2
copy ..\.pio\build\due-5100\firmware.bin due-5100
copy ..\.pio\build\mega2560-5100\firmware.hex mega2560-5100
copy ..\.pio\build\due-5500\firmware.bin due-5500
copy ..\.pio\build\nrf52840\firmware.hex nrf52840-5500
copy ..\.pio\build\esp32-wifi\firmware.bin esp32-wifi
copy ..\.pio\build\stm32-enc2860\firmware.bin stm32-enc2860
copy ..\.pio\build\esp8266-wifi\firmware.bin esp8266-wifi
copy ..\.pio\build\lighthub21\firmware.bin lighthub21
copy ..\.pio\build\mega2560-5500\firmware.hex mega2560-5500

View File

@@ -0,0 +1,25 @@
{
"syslog":["95.31.43.9"],
"items": {
"ledhum":[6,-13],
"reghum": [13, [
[50, 10, 0, 60, 250, 200], [{"item": "relayhum"}, {"item":"ledhum"}]
], 30, 12],
"relayhum": [16, [12, 1200], 255, 2]
},
"in":{
"0":{"T":0,
"click":{ "item":"reghum","icmd":"TOGGLE"},
"dclick":{ "emit":"myhome/light-d2/light","ecmd":"TOGGLE"}
},
"3":{"T":4,
"temp":{"emit":"plugtemp"},
"hum":{"item":"reghum/val","emit":"plughum"}
}
},
"mqtt":["plug00","192.168.88.2"]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,3 @@
mode com3:1200,n,8,1
pause
..\tools\win\tool-bossac\bossac.exe -i --port=com3 -U false -e -w -v -b firmware.bin -R

View File

@@ -1,6 +1,8 @@
import os
Import("env")
script = env.GetProjectOption("_upload_command")
script = env.GetProjectOption("_upload_command")
spath = os.path.abspath(script)
#env.Replace(
# UPLOADER="executable or path to executable",
# UPLOADCMD=script
@@ -8,5 +10,4 @@ script = env.GetProjectOption("_upload_command")
env.AddCustomTarget(
"ota",
"$BUILD_DIR/${PROGNAME}.bin",
script
)
spath)

18
ldscripts/bootloader.ld Normal file
View File

@@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RE boards, using the generic bootloader (which takes the lower 8k of memory)
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
rom (rx) : ORIGIN = 0x08002000, LENGTH = 504K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE ldscripts/common.inc

220
ldscripts/common.inc Normal file
View File

@@ -0,0 +1,220 @@
/*
* Linker script for libmaple.
*
* Original author "lanchon" from ST forums, with modifications by LeafLabs.
*/
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
/*
* Configure other libraries we want in the link.
*
* libgcc, libc, and libm are common across supported toolchains.
* However, some toolchains require additional archives which aren't
* present everywhere (e.g. ARM's gcc-arm-embedded releases).
*
* To hack around this, we let the build system specify additional
* archives by putting the right extra_libs.inc (in a directory under
* toolchains/) in our search path.
*/
GROUP(libgcc.a libc.a libm.a)
INCLUDE ldscripts/extra_libs.inc
/*
* These force the linker to search for vector table symbols.
*
* These symbols vary by STM32 family (and also within families).
* It's up to the build system to configure the link's search path
* properly for the target MCU.
*/
INCLUDE ldscripts/vector_symbols.inc
/* STM32 vector table. */
EXTERN(__stm32_vector_table)
/* C runtime initialization function. */
EXTERN(start_c)
/* main entry point */
EXTERN(main)
/* Initial stack pointer value. */
EXTERN(__msp_init)
PROVIDE(__msp_init = ORIGIN(ram) + LENGTH(ram));
/* Reset vector and chip reset entry point */
EXTERN(__start__)
ENTRY(__start__)
PROVIDE(__exc_reset = __start__);
/* Heap boundaries, for libmaple */
EXTERN(_lm_heap_start);
EXTERN(_lm_heap_end);
SECTIONS
{
.text :
{
__text_start__ = .;
/*
* STM32 vector table. Leave this here. Yes, really.
*/
*(.stm32.interrupt_vector)
/*
* Program code and vague linking
*/
*(.text .text.* .gnu.linkonce.t.*)
*(.plt)
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
*(.ARM.extab* .gnu.linkonce.armextab.*)
*(.gcc_except_table)
*(.eh_frame_hdr)
*(.eh_frame)
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
} > REGION_TEXT
/*
* End of text
*/
.text.align :
{
. = ALIGN(8);
__text_end__ = .;
} > REGION_TEXT
/*
* .ARM.exidx exception unwinding; mandated by ARM's C++ ABI
*/
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > REGION_RODATA
__exidx_end = .;
/*
* .data
*/
.data :
{
__data_start__ = .;
LONG(0)
. = ALIGN(8);
*(.got.plt) *(.got)
*(.data .data.* .gnu.linkonce.d.*)
. = ALIGN(8);
__data_end__ = .;
} > REGION_DATA AT> REGION_RODATA
/*
* Read-only data
*/
.rodata :
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
/* .USER_FLASH: We allow users to allocate into Flash here */
*(.USER_FLASH)
/* ROM image configuration; for C startup */
. = ALIGN(4);
_lm_rom_img_cfgp = .;
LONG(LOADADDR(.data));
/*
* Heap: Linker scripts may choose a custom heap by overriding
* _lm_heap_start and _lm_heap_end. Otherwise, the heap is in
* internal SRAM, beginning after .bss, and growing towards
* the stack.
*
* I'm shoving these here naively; there's probably a cleaner way
* to go about this. [mbolivar]
*/
_lm_heap_start = DEFINED(_lm_heap_start) ? _lm_heap_start : _end;
_lm_heap_end = DEFINED(_lm_heap_end) ? _lm_heap_end : __msp_init;
} > REGION_RODATA
/*
* .bss
*/
.bss :
{
. = ALIGN(8);
__bss_start__ = .;
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
__bss_end__ = .;
_end = __bss_end__;
} > REGION_BSS
/*
* Debugging sections
*/
.stab 0 (NOLOAD) : { *(.stab) }
.stabstr 0 (NOLOAD) : { *(.stabstr) }
/* DWARF debug sections.
* Symbols in the DWARF debugging sections are relative to the beginning
* of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) }
}

7
ldscripts/extra_libs.inc Normal file
View File

@@ -0,0 +1,7 @@
/*
* Extra archives needed by ARM's GCC ARM Embedded arm-none-eabi-
* releases (https://launchpad.net/gcc-arm-embedded/).
*/
/* This is for the provided newlib. */
GROUP(libnosys.a)

26
ldscripts/flash.ld Normal file
View File

@@ -0,0 +1,26 @@
/*
* libmaple linker script for "Flash" builds.
*
* A Flash build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but offsets the sections by
* enough space to store the Maple bootloader, which lives in low
* Flash and uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-flash.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE ldscripts/common.inc

31
ldscripts/jtag.ld Normal file
View File

@@ -0,0 +1,31 @@
/*
* libmaple linker script for "JTAG" builds.
*
* A "JTAG" build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but links starting at the
* Flash and SRAM starting addresses (0x08000000 and 0x20000000
* respectively). This will wipe out a Maple bootloader if there's one
* on the board, so only use this if you know what you're doing.
*
* Of course, a "JTAG" build is perfectly usable for upload over SWD,
* the system memory bootloader, etc. The name is just a historical
* artifact.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-jtag.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE ldscripts/common.inc

46
ldscripts/ldscript.ld Normal file
View File

@@ -0,0 +1,46 @@
/*
!!!!!!!!!!!! STM32Duino default linker script
* This script extends the default linker script to add a .noinit
* section. This section is just mapped to RAM, but it is emitted
* separately from the .data and .bss sections (both of which are
* initialized by startup code), so any variables in this section are
* untouched on startup (so they survive across resets).
*
* This script is intended to supplied to the linker's -T / --script
* option as the primary linker script. When the linker sees an INSERT
* command, this will cause it to *also* read the default linker script
* (after reading this script) and then executing the INSERT commands
* after both scripts have been read.
*
* Note that parsing of linker scripts is a bit peculiar, e.g. INSERT
* does not textually inserts, it inserts any generated output sections.
* Also, because this script is read *first*, we cannot refer to things
* in the default script. In particular, it would make sense to add >
* RAM to the output section below to ensure that the section is mapped
* into RAM, but the RAM region is not defined yet (I think it would
* work though, but produces warnings). Instead, we just rely on the
* defaults used by the linker: If no region is defined for an output
* section, it will just map to first address after the previous section
* (.bss in this case, which is fine).
*/
SECTIONS
{
/* Define a noinit output section and mark it as NOLOAD to prevent
* putting its contents into the resulting .bin file (which is the
* default). */
.noinit (NOLOAD) :
{
/* Ensure output is aligned */
. = ALIGN(4);
/* Define a global _snoinit (and _enoinit below) symbol just in case
* code wants to iterate over all noinit variables for some reason */
_snoinit = .;
/* Actually import the .noinit and .noinit* import sections */
*(.noinit)
*(.noinit*)
. = ALIGN(4);
_enoinit = .;
}
}
INSERT AFTER .bss;

5
ldscripts/mem-flash.inc Normal file
View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 492K
}

5
ldscripts/mem-jtag.inc Normal file
View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
}

5
ldscripts/mem-ram.inc Normal file
View File

@@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
}

25
ldscripts/ram.ld Normal file
View File

@@ -0,0 +1,25 @@
/*
* libmaple linker script for RAM builds.
*
* A Flash build puts .text, .rodata, and .data/.bss/heap (of course)
* in SRAM, but offsets the sections by enough space to store the
* Maple bootloader, which uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-ram.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", ram);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", ram);
/* Let common.inc handle the real work. */
INCLUDE ldscripts/common.inc

18
ldscripts/stm32f103rb.ld Normal file
View File

@@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RB boards.
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE ldscripts/common.inc

View File

@@ -0,0 +1,17 @@
/*
* Linker script for Generic STM32F103RB boards, using the generic bootloader (which takes the lower 8k of memory)
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08002000, LENGTH = 120K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE ldscripts/common.inc

18
ldscripts/stm32f103rc.ld Normal file
View File

@@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RC boards.
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE ldscripts/common.inc

View File

@@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RC boards, using the generic bootloader (which takes the lower 8k of memory)
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K
rom (rx) : ORIGIN = 0x08002000, LENGTH = 248K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE ldscripts/common.inc

18
ldscripts/stm32f103re.ld Normal file
View File

@@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RE boards.
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE ldscripts/common.inc

View File

@@ -0,0 +1,78 @@
EXTERN(__msp_init)
EXTERN(__exc_reset)
EXTERN(__exc_nmi)
EXTERN(__exc_hardfault)
EXTERN(__exc_memmanage)
EXTERN(__exc_busfault)
EXTERN(__exc_usagefault)
EXTERN(__stm32reservedexception7)
EXTERN(__stm32reservedexception8)
EXTERN(__stm32reservedexception9)
EXTERN(__stm32reservedexception10)
EXTERN(__exc_svc)
EXTERN(__exc_debug_monitor)
EXTERN(__stm32reservedexception13)
EXTERN(__exc_pendsv)
EXTERN(__exc_systick)
EXTERN(__irq_wwdg)
EXTERN(__irq_pvd)
EXTERN(__irq_tamper)
EXTERN(__irq_rtc)
EXTERN(__irq_flash)
EXTERN(__irq_rcc)
EXTERN(__irq_exti0)
EXTERN(__irq_exti1)
EXTERN(__irq_exti2)
EXTERN(__irq_exti3)
EXTERN(__irq_exti4)
EXTERN(__irq_dma1_channel1)
EXTERN(__irq_dma1_channel2)
EXTERN(__irq_dma1_channel3)
EXTERN(__irq_dma1_channel4)
EXTERN(__irq_dma1_channel5)
EXTERN(__irq_dma1_channel6)
EXTERN(__irq_dma1_channel7)
EXTERN(__irq_adc)
EXTERN(__irq_usb_hp_can_tx)
EXTERN(__irq_usb_lp_can_rx0)
EXTERN(__irq_can_rx1)
EXTERN(__irq_can_sce)
EXTERN(__irq_exti9_5)
EXTERN(__irq_tim1_brk)
EXTERN(__irq_tim1_up)
EXTERN(__irq_tim1_trg_com)
EXTERN(__irq_tim1_cc)
EXTERN(__irq_tim2)
EXTERN(__irq_tim3)
EXTERN(__irq_tim4)
EXTERN(__irq_i2c1_ev)
EXTERN(__irq_i2c1_er)
EXTERN(__irq_i2c2_ev)
EXTERN(__irq_i2c2_er)
EXTERN(__irq_spi1)
EXTERN(__irq_spi2)
EXTERN(__irq_usart1)
EXTERN(__irq_usart2)
EXTERN(__irq_usart3)
EXTERN(__irq_exti15_10)
EXTERN(__irq_rtcalarm)
EXTERN(__irq_usbwakeup)
EXTERN(__irq_tim8_brk)
EXTERN(__irq_tim8_up)
EXTERN(__irq_tim8_trg_com)
EXTERN(__irq_tim8_cc)
EXTERN(__irq_adc3)
EXTERN(__irq_fsmc)
EXTERN(__irq_sdio)
EXTERN(__irq_tim5)
EXTERN(__irq_spi3)
EXTERN(__irq_uart4)
EXTERN(__irq_uart5)
EXTERN(__irq_tim6)
EXTERN(__irq_tim7)
EXTERN(__irq_dma2_channel1)
EXTERN(__irq_dma2_channel2)
EXTERN(__irq_dma2_channel3)
EXTERN(__irq_dma2_channel4_5)

View File

@@ -10,7 +10,7 @@ extern PubSubClient mqttClient;
extern int8_t ethernetIdleCount;
int abstractCh::publishTopic(const char* topic, long value, const char* subtopic)
{
{
char valstr[16];
printUlongValueToStr(valstr, value);
return publishTopic(topic, valstr,subtopic);
@@ -19,7 +19,7 @@ int abstractCh::publishTopic(const char* topic, long value, const char* subtopic
int abstractCh::publishTopic(const char* topic, float value, const char* subtopic)
{
char valstr[16];
printFloatValueToStr(value, valstr);
printFloatValueToStr(valstr, value);
return publishTopic(topic, valstr,subtopic);
};

View File

@@ -3,7 +3,7 @@
#define CST_UNKNOWN 0
#define CST_INITIALIZED 1
#define CST_FAILED 2
#define CST_FAILED -1
class abstractCh {
public:

View File

@@ -20,7 +20,7 @@ int abstractIn::publish(long value, const char* subtopic)
int abstractIn::publish(float value, const char* subtopic)
{
char valstr[16];
printFloatValueToStr(value, valstr);
printFloatValueToStr(valstr, value);
return publish(valstr,subtopic);
};

View File

@@ -12,6 +12,8 @@ int abstractOut::isActive()
case CMD_VOID:
return 0;
break;
case CMD_ON: //trying (PWM ON set=0 issue)
return 1;
default:
st.loadItem(item);
return st.getPercents255();

View File

@@ -10,6 +10,7 @@ public:
abstractOut(Item * _item):abstractCh(){item=_item;};
virtual int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true) =0;
virtual int isActive();
virtual bool isAllowed(itemCmd cmd){return true;};
virtual itemCmd getDefaultOnVal(){return itemCmd().Percents255(255);};
virtual int getChanType(){return 0;}
virtual int getDefaultStorageType(){return 0;} /// Remove?? Now getChanType used instead

View File

@@ -71,16 +71,16 @@ case S_CMD:
{
cmd.setPercents(INIT_VOLUME);
cmd.saveItem(item);
item->SendStatus(SEND_PARAMETERS | SEND_DEFFERED);
item->SendStatus(FLAG_PARAMETERS | FLAG_SEND_DEFFERED);
};
PixelCtrl(cmd,subItem, true);
// item->SendStatus(SEND_COMMAND | SEND_PARAMETERS );
// item->SendStatus(FLAG_COMMAND | FLAG_PARAMETERS );
return 1;
case CMD_OFF:
cmd.param.asInt32=0;
PixelCtrl(cmd, subItem, true);
// item->SendStatus(SEND_COMMAND);
// item->SendStatus(FLAG_COMMAND);
return 1;
default:

View File

@@ -293,6 +293,19 @@ bool systemConfig::setConfigFlags(systemConfigFlags flags)
return setConfigFlags(flags);
}
bool systemConfig::getDHCPfallback()
{
systemConfigFlags flags = getConfigFlags();
return flags.dhcpFallback;
}
bool systemConfig::setDHCPfallback(bool flag)
{
systemConfigFlags flags = getConfigFlags();
flags.dhcpFallback=flag;
return setConfigFlags(flags);
}
bool systemConfig::getLoadHTTPConfig()
{
systemConfigFlags flags = getConfigFlags();

View File

@@ -61,6 +61,9 @@ class systemConfig {
bool saveETAG();
bool loadETAG();
bool getDHCPfallback();
bool setDHCPfallback(bool flag);
systemConfigFlags getConfigFlags();
bool setConfigFlags(systemConfigFlags flags);

View File

@@ -8,7 +8,7 @@
#endif
#if defined(ARDUINO_ARCH_AVR)
#if defined(ARDUINO_ARCH_AVR)
#include <EEPROM.h>
#endif
@@ -31,14 +31,19 @@ extern DueFlashStorage EEPROM;
extern NRFFlashStorage EEPROM;
#endif
#ifdef ARDUINO_ARCH_STM32
#include <NRFFlashStorage.h> //STUB
extern NRFFlashStorage EEPROM;
#endif
//#ifdef ARDUINO_ARCH_STM32
//#include <NRFFlashStorage.h> //STUB
//extern NRFFlashStorage EEPROM;
// static char samBuffer[64];
// short samBufferPos = 0;
//#endif
#if defined(__SAM3X8E__)
DueFlashStorage EEPROM;
static char samBuffer[64];
short samBufferPos = 0;
#endif
#ifdef NRF5
@@ -46,7 +51,10 @@ NRFFlashStorage EEPROM;
#endif
#ifdef ARDUINO_ARCH_STM32
NRFFlashStorage EEPROM;
//NRFFlashStorage EEPROM;
#include <EEPROM.h>
#define DATA_LENGTH E2END
//FLASH_PAGE_SIZE = 0x400
#endif
#if defined(FS_STORAGE)
@@ -114,7 +122,7 @@ NRFFlashStorage EEPROM;
debugSerial<<(F(" Res:"))<<res<<endl;
return res;
};
void flashStream::close() {fs.close(); debugSerial<<filename<<" Closed\n";};
void flashStream::close() {fs.flush();fs.close(); debugSerial<<filename<<" Closed\n";};
void flashStream::flush() {fs.flush(); debugSerial<<filename<<" Flushed\n";};
size_t flashStream::write(uint8_t ch)
{
@@ -129,6 +137,15 @@ NRFFlashStorage EEPROM;
int flashStream::open(short fileNum, char mode)
{
#if defined(__SAM3X8E__) //|| defined (ARDUINO_ARCH_STM32)
if (samBufferPos) flush();
samBufferPos = 0;
#endif
#if defined (ARDUINO_ARCH_STM32)
eeprom_buffer_fill();
#endif
switch (fileNum) {
case FN_CONFIG_JSON:
pos = 0;
@@ -138,6 +155,7 @@ NRFFlashStorage EEPROM;
#ifdef OTA
contentType = HTTP_TEXT_JSON;
#endif
openmode = mode;
return 1;
case FN_CONFIG_BIN:
@@ -148,6 +166,7 @@ NRFFlashStorage EEPROM;
#ifdef OTA
contentType = HTTP_OCTET_STREAM;
#endif
openmode = mode;
return 1;
default:
@@ -171,7 +190,17 @@ NRFFlashStorage EEPROM;
};
unsigned int flashStream::seek(unsigned int _pos)
{ pos=min(_pos, streamSize);
{
#if defined(__SAM3X8E__) //|| defined (ARDUINO_ARCH_STM32)
if (samBufferPos) flush();
#endif
#if defined (ARDUINO_ARCH_STM32)
//eeprom_buffer_flush();
#endif
pos=min(_pos, streamSize);
//debugSerial<<F("Seek:")<<pos<<endl;
return pos;
};
@@ -196,27 +225,58 @@ NRFFlashStorage EEPROM;
else return -1;
};
void flashStream::flush() {
#if defined(ESP8266) || defined(ESP32)
if (EEPROM.commitReset())
infoSerial<<"Commited to FLASH"<<endl;
else errorSerial<<"Commit error. len:"<<EEPROM.length()<<endl;
#elif defined(__SAM3X8E__) //|| defined (ARDUINO_ARCH_STM32)
if (samBufferPos)
EEPROM.write(startPos+pos-samBufferPos,(byte*)samBuffer,samBufferPos);
samBufferPos=0;
#elif defined (ARDUINO_ARCH_STM32)
eeprom_buffer_flush();
#endif
};
size_t flashStream::write(uint8_t ch)
{
#if defined(__AVR__)
EEPROM.update(startPos+pos++,(char)ch);
return 1;
#elif defined(__SAM3X8E__)
return EEPROM.write(startPos+pos++,(char)ch);
#elif defined(__SAM3X8E__)// || defined (ARDUINO_ARCH_STM32)
if (samBufferPos==sizeof(samBuffer))
{
samBufferPos = 0;
EEPROM.write(startPos+pos-sizeof(samBuffer),(byte*)samBuffer,sizeof(samBuffer));
}
samBuffer[samBufferPos++]=ch;
pos++;
return 1;
// return EEPROM.write(startPos+pos++,(char)ch);
#elif defined (ARDUINO_ARCH_STM32)
if (startPos+pos<=DATA_LENGTH)
{
eeprom_buffered_write_byte(startPos+pos++,(char)ch);
return 1;
}
else
{
errorSerial<<F("Flash sector exceeded")<<endl;
return 0;
}
#else
EEPROM.write(startPos+pos++,(char)ch);
return 1;
#endif
};
/*
#if defined(__SAM3X8E__)
size_t flashStream::write(const uint8_t *buffer, size_t size)
{
@@ -226,7 +286,7 @@ NRFFlashStorage EEPROM;
};
#endif
*/
#if defined(ESP8266) || defined(ESP32)
void flashStream::putEOF()
{
@@ -237,7 +297,14 @@ NRFFlashStorage EEPROM;
void flashStream::close()
{
putEOF();
if (openmode == 'w')
{
putEOF();
debugSerial<<F("EOF")<<endl;
}
#if defined(__SAM3X8E__)
if (samBufferPos) flush();
#endif
}

View File

@@ -53,9 +53,10 @@ class flashStream : public seekableStream
protected:
unsigned int pos;
unsigned int startPos;
char openmode ;
public:
flashStream():seekableStream(MAX_STREAM_SIZE){};
flashStream():seekableStream(MAX_STREAM_SIZE){openmode = '\0';};
void setSize(unsigned int _size);
int open(short fileNum, char mode='\0') ;
virtual int open(String _filename, char mode='\0') override;
@@ -66,11 +67,11 @@ public:
virtual void flush();
virtual size_t write(uint8_t ch) ;
#if defined(__SAM3X8E__)
virtual size_t write(const uint8_t *buffer, size_t size) override;
#else
//#if defined(__SAM3X8E__)
//virtual size_t write(const uint8_t *buffer, size_t size) override;
//#else
using Print::write;//(const uint8_t *buffer, size_t size);
#endif
//#endif
#if defined(ESP8266) || defined(ESP32)
virtual void putEOF() override ;

View File

@@ -464,6 +464,8 @@ void Input::dht22Poll() {
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
DHTesp dhtSensor;
dhtSensor.setup(pin, DHTesp::DHT22);
//pinMode(pin, INPUT_PULLUP);
//digitalWrite(pin, LOW); // Switch bus to receive data
TempAndHumidity dhtSensorData = dhtSensor.getTempAndHumidity();
float temp = roundf(dhtSensorData.temperature * 10) / 10;
float humidity = roundf(dhtSensorData.humidity);
@@ -479,8 +481,8 @@ debugSerial << F("IN:") << pin << F(" DHT22 type. T=") << temp << F("°C H=") <<
// New tyle unified activities
aJsonObject *actT = aJson.getObjectItem(inputObj, "temp");
aJsonObject *actH = aJson.getObjectItem(inputObj, "hum");
executeCommand(actT,-1,itemCmd(temp));
executeCommand(actH,-1,itemCmd(humidity));
if (!isnan(temp)) executeCommand(actT,-1,itemCmd(temp));
if (!isnan(humidity)) executeCommand(actH,-1,itemCmd(humidity));
//Legacy action conf - TODO - remove in further releases
aJsonObject *emit = aJson.getObjectItem(inputObj, "emit");
@@ -503,11 +505,11 @@ debugSerial << F("IN:") << pin << F(" DHT22 type. T=") << temp << F("°C H=") <<
strncpy(addrstr, emit->valuestring, sizeof(addrstr));
if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestring);
strcat(addrstr, "T");
printFloatValueToStr(temp, valstr);
printFloatValueToStr(valstr, temp);
if (mqttClient.connected() && !ethernetIdleCount)
mqttClient.publish(addrstr, valstr);
addrstr[strlen(addrstr) - 1] = 'H';
printFloatValueToStr(humidity, valstr);
printFloatValueToStr(valstr, humidity);
if (mqttClient.connected() && !ethernetIdleCount)
mqttClient.publish(addrstr, valstr);
@@ -1021,7 +1023,7 @@ void Input::onAnalogChanged(itemCmd newValue) {
strncpy(addrstr,emit->valuestring,sizeof(addrstr));
if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestring);
char strVal[16];
newValue.toString(strVal,sizeof(strVal),SEND_PARAMETERS);
newValue.toString(strVal,sizeof(strVal),FLAG_PARAMETERS);
if (mqttClient.connected() && !ethernetIdleCount)
mqttClient.publish(addrstr, strVal, true);

View File

@@ -541,9 +541,9 @@ void setupIpmodbus(){
// Calculate Modbus RTU character timeout and frame delay
byte bits = // number of bits per character (11 in default Modbus RTU settings)
1 + // start bit
(((MODBUS_DIMMER_PARAM & 0x06) >> 1) + 5) + // data bits
(((MODBUS_DIMMER_PARAM & 0x08) >> 3) + 1); // stop bits
if (((MODBUS_DIMMER_PARAM & 0x30) >> 4) > 1) bits += 1; // parity bit (if present)
(((MODBUS_SERIAL_PARAM & 0x06) >> 1) + 5) + // data bits
(((MODBUS_SERIAL_PARAM & 0x08) >> 3) + 1); // stop bits
if (((MODBUS_SERIAL_PARAM & 0x30) >> 4) > 1) bits += 1; // parity bit (if present)
//bits = 11;
int T = ((unsigned long)bits * 1000000UL) / MODBUS_SERIAL_BAUD; // time to send 1 character over serial in microseconds

File diff suppressed because it is too large Load Diff

View File

@@ -31,11 +31,13 @@ e-mail anklimov@gmail.com
#define S_RGB 6
#define S_FAN 7
#define S_MODE 8
#define S_HUE 9
#define S_SAT 10
#define S_TEMP 11
#define S_RAW 12
#define S_ADDITIONAL 12
#define S_CTRL 9
#define S_HUE 10
#define S_SAT 11
#define S_TEMP 12
#define S_RAW 13
#define S_ADDITIONAL 13
#define CH_DIMMER 0 //DMX 1-4 ch
#define CH_RGBW 1 //DMX 4 ch
@@ -59,6 +61,7 @@ e-mail anklimov@gmail.com
#define CH_ELEVATOR 19
#define CH_COUNTER 20
#define CH_HUMIDIFIER 21
#define CH_MERCURY 22
//#define CHANNEL_TYPES 13
@@ -131,9 +134,9 @@ class Item
chPersistent * getPersistent();
chPersistent * setPersistent(chPersistent * par);
void setCmd(uint8_t cmdValue);
short getFlag (short flag=FLAG_MASK);
void setFlag (short flag);
void clearFlag (short flag);
uint32_t getFlag (uint32_t flag=FLAG_MASK);
void setFlag (uint32_t flag);
void clearFlag (uint32_t flag);
void setVal(long int par);
void setFloatVal(float par);
void setSubtype(uint8_t par);
@@ -145,6 +148,9 @@ class Item
inline int On (){return Ctrl(itemCmd(ST_VOID,CMD_ON));};
inline int Off(){return Ctrl(itemCmd(ST_VOID,CMD_OFF));};
inline int Toggle(){return Ctrl(itemCmd(ST_VOID,CMD_TOGGLE));};
int scheduleCommand(itemCmd cmd);
int scheduleOppositeCommand(itemCmd cmd);
int isScheduled();
protected:
long int limitSetValue();

View File

@@ -4,6 +4,7 @@
#include "Streaming.h"
#include "item.h"
#include "bright.h"
#include <utility/stringbuffer.h>>
#ifndef HSV_DISABLE
#ifdef ADAFRUIT_LED
@@ -108,6 +109,7 @@ uint8_t itemCmd::getStoragetypeByChanType(short chanType)
case CH_PWM:
case CH_VC:
case CH_MODBUS:
//case CH_RELAY:
//case CH_GROUP:
return ST_PERCENTS255;
break;
@@ -1047,18 +1049,22 @@ bool itemCmd::loadItem(Item * item, uint16_t optionsFlag)
if (item && item->isValid())
{
short subtype =item->getSubtype();
if (optionsFlag & SEND_COMMAND) cmd.cmdCode = item->getCmd();
if (optionsFlag & FLAG_COMMAND) cmd.cmdCode = item->getCmd();
//if (optionsFlag & FLAG_FLAGS)
// if (item->getFlag(FLAG_DISABLED))
// cmd.cmdCode = CMD_DISABLE;
if (subtype)
{
cmd.itemArgType= subtype;
if (optionsFlag & SEND_PARAMETERS) param.asInt32 = item->itemVal->valueint;
if (optionsFlag & FLAG_PARAMETERS) param.asInt32 = item->itemVal->valueint;
//debugSerial<<F("Loaded :");
//debugOut();
return true;
}
if (optionsFlag & SEND_PARAMETERS)
if (optionsFlag & FLAG_PARAMETERS)
switch (item->itemVal->type)
{
case aJson_Int:
@@ -1091,7 +1097,7 @@ bool itemCmd::loadItemDef(Item * item, uint16_t optionsFlag)
setDefault();
saveItem(item);
debugOut();
item->SendStatus(SEND_PARAMETERS | SEND_DEFFERED);
item->SendStatus(FLAG_PARAMETERS | FLAG_SEND_DEFFERED);
return false;
}
return true;
@@ -1101,8 +1107,38 @@ bool itemCmd::saveItem(Item * item, uint16_t optionsFlag)
{
if (item && item->isValid())
{
if (optionsFlag & SEND_COMMAND) item->setCmd(cmd.cmdCode);
if (optionsFlag & SEND_PARAMETERS)
if (optionsFlag & FLAG_FLAGS)
switch (cmd.cmdCode)
{
case CMD_DISABLE:
item->setFlag(FLAG_DISABLED);
break;
case CMD_ENABLE:
item->clearFlag(FLAG_DISABLED);
item->clearFlag(FLAG_FREEZED);
break;
case CMD_FREEZE:
item->setFlag(FLAG_FREEZED);
break;
case CMD_UNFREEZE:
item->clearFlag(FLAG_FREEZED);
break;
}
if (optionsFlag & FLAG_COMMAND)
switch (cmd.cmdCode)
{
case CMD_DISABLE:
case CMD_ENABLE:
case CMD_FREEZE:
case CMD_UNFREEZE:
break;
default:
item->setCmd(cmd.cmdCode);
}
if (optionsFlag & FLAG_PARAMETERS)
switch (cmd.itemArgType)
{
case ST_FLOAT:
@@ -1135,7 +1171,7 @@ return false;
int cmd = txt2cmd(verb->valuestring);
if (cmd>0)
{
free(verb->valuestring);
freeString(verb->valuestring);
verb->valueint=cmd;
verb->type=aJson_Int;
return verb->valueint;
@@ -1181,6 +1217,7 @@ return false;
i=i->next;
}
}
break;
case aJson_String:
if (strcmp(cmdMapping->valuestring,"fan")==0)
switch (getCmd())
@@ -1209,7 +1246,10 @@ return false;
} //switch
if (matchedCmd) return itemCmd().Int((uint32_t)matchedCmd->valueint);
if (matchedCmd && matchedCmd->type != aJson_NULL)
{
return itemCmd().Int((uint32_t)matchedCmd->valueint);
}
aJsonObject *valMapping = aJson.getObjectItem(mappingData, "val");
if (isValue() && valMapping && valMapping->type == aJson_Array && aJson.getArraySize(valMapping) == 4)
@@ -1220,6 +1260,7 @@ if (isValue() && valMapping && valMapping->type == aJson_Array && aJson.getArray
aJson.getArrayItem(valMapping,0)->valueint,aJson.getArrayItem(valMapping,1)->valueint,
aJson.getArrayItem(valMapping,2)->valueint,aJson.getArrayItem(valMapping,3)->valueint));
}
else if (valMapping && valMapping->type == aJson_NULL) return itemCmd(ST_VOID,CMD_VOID);
return *this;
}
@@ -1237,10 +1278,10 @@ if (isValue() && valMapping && valMapping->type == aJson_Array && aJson.getArray
case aJson_Array:
{
aJsonObject *i = cmdMapping->child;
//if first array element is not array - this is default mapping value
//if first array element is not array - this is default mapping value, no reverse mapping, skipping
if (i && i->type==aJson_Int)
{
matchedCmd = i;
//matchedCmd = i;
i=i->next;
}
@@ -1296,6 +1337,7 @@ if (valMapping && valMapping->type == aJson_Array && aJson.getArraySize(valMappi
int diff = ((b-a)/(d-c))/2;
return itemCmd().Int((uint32_t) constrain(map(getInt(),c,d,a,b)+diff,0,255));
}
if (valMapping && valMapping->type == aJson_NULL) return itemCmd();
return *this;
}
@@ -1306,17 +1348,17 @@ char * itemCmd::toString(char * Buffer, int bufLen, int sendFlags, bool scale100
if (!Buffer || !bufLen) return NULL;
*Buffer=0;
char * argPtr=Buffer;
if (isCommand() && (sendFlags & SEND_COMMAND))
if (isCommand() && (sendFlags & FLAG_COMMAND))
{
int len;
strncpy_P(Buffer, commands_P[cmd.cmdCode], bufLen);
if (isValue() && (sendFlags & SEND_PARAMETERS)) strncat(Buffer, " ", bufLen);
if (isValue() && (sendFlags & FLAG_PARAMETERS)) strncat(Buffer, " ", bufLen);
len=strlen(Buffer);
argPtr+=len;
bufLen-=len;
bufLen--;
}
if (isValue() && (sendFlags & SEND_PARAMETERS))
if (isValue() && (sendFlags & FLAG_PARAMETERS))
{
//strncat(Buffer, " ", bufLen);
//bufLen--;
@@ -1335,7 +1377,10 @@ char * itemCmd::toString(char * Buffer, int bufLen, int sendFlags, bool scale100
snprintf(argPtr, bufLen, "%ld", param.asInt32);
break;
case ST_TENS:
snprintf(argPtr, bufLen, "%ld.%0"QUOTE(TENS_FRACT_LEN)"d", param.asInt32/TENS_BASE, abs(param.asInt32 % TENS_BASE));
if (param.asInt32<0)
snprintf(argPtr, bufLen, "-%ld.%0"QUOTE(TENS_FRACT_LEN)"d", abs(param.asInt32)/TENS_BASE, abs(param.asInt32 % TENS_BASE));
else
snprintf(argPtr, bufLen, "%ld.%0"QUOTE(TENS_FRACT_LEN)"d", param.asInt32/TENS_BASE, abs(param.asInt32 % TENS_BASE));
break;
case ST_HSV255:
colorTemp=getColorTemp();

View File

@@ -26,8 +26,10 @@ typedef char cmdstr[9];
const cmdstr commands_P[] PROGMEM =
{
"","ON","OFF","REST","TOGGLE","HALT","XON","XOFF","INCREASE","DECREASE",
"HEAT","COOL","AUTO","FAN_ONLY","DRY","STOP","HIGH","MEDIUM","LOW","ENABLE","DISABLE",
"TRUE","FALSE","RGB","HSV"
"ENABLE","DISABLE","UNFREEZE","FREEZE",
"AUTO","FAN_ONLY",
"HIGH","MEDIUM","LOW",
"HEAT","COOL","DRY","STOP","RGB","HSV"
};
#define commandsNum sizeof(commands_P)/sizeof(cmdstr)
@@ -41,37 +43,50 @@ const cmdstr commands_P[] PROGMEM =
#define CMD_XOFF 7 /// OFF only if was previously turned on by CMD_XON
#define CMD_UP 8 /// increase
#define CMD_DN 9 /// decrease
#define CMD_HEAT 0xa /// Thermostat/AC set to HEATing mode
#define CMD_COOL 0xb /// Thermostat/AC set to COOLing mode
#define CMD_AUTO 0xc /// Thermostat/AC set to Auto mode
#define CMD_FAN 0xd /// AC set to Fan-only mode
#define CMD_DRY 0xe /// AC set to Dry mode
#define CMD_STOP 0xf /// stop dimming (for further use)
#define CMD_ENABLE 0xa /// for PID regulator and XON/XOFF - chan limitation
#define CMD_DISABLE 0xb /// for PID regulator
#define CMD_UNFREEZE 0xc /// Aliase for ON
#define CMD_FREEZE 0xd /// Aliase for OFF
#define CMD_AUTO 0xe /// Thermostat/AC set to Auto mode
#define CMD_FAN 0xf /// AC set to Fan-only mode
#define CMD_HIGH 0x10 /// AC/Vent fan level HIGH
#define CMD_MED 0x11 /// AC/Vent fan level MEDIUM
#define CMD_LOW 0x12 /// AC/Vent fan level LOW
#define CMD_ENABLE 0x13 /// for PID regulator
#define CMD_DISABLE 0x14 /// for PID regulator
#define CMD_TRUE 0x15 /// Aliase for ON
#define CMD_FALSE 0x16 /// Aliase for OFF
#define CMD_HEAT 0x13 /// Thermostat/AC set to HEATing mode
#define CMD_COOL 0x14 /// Thermostat/AC set to COOLing mode
#define CMD_DRY 0x15 /// AC set to Dry mode
#define CMD_STOP 0x16 /// stop dimming (for further use)
#define CMD_RGB 0x17
#define CMD_HSV 0x18
#define CMD_MASK 0xff
#define FLAG_MASK 0xff00
#define CMD_MASK 0xffUL
#define FLAG_MASK 0x00ffff00UL
//#define STATE_MASK 0xff0000
#define CMD_VOID 0
#define CMD_UNKNOWN -1
#define CMD_JSON -2
#define SEND_IMMEDIATE 0x1
#define SEND_COMMAND 0x100
#define SEND_PARAMETERS 0x200
#define SEND_RETRY 0x400
#define SEND_DEFFERED 0x800
#define SEND_DELAYED 0x1000
#define ACTION_NEEDED 0x2000
#define ACTION_IN_PROCESS 0x4000
//FLAGS
#define FLAG_SEND_IMMEDIATE 0x1UL
#define FLAG_COMMAND 0x100UL
#define FLAG_PARAMETERS 0x200UL
#define FLAG_FLAGS 0x400UL
#define FLAG_SEND_RETRY 0x800UL
#define FLAG_SEND_DEFFERED 0x1000UL
#define FLAG_SEND_DELAYED 0x2000UL
#define FLAG_ACTION_NEEDED 0x4000UL
#define FLAG_ACTION_IN_PROCESS 0x8000UL
#define FLAG_DISABLED 0x10000UL
#define FLAG_FREEZED 0x20000UL
#define FLAG_HALTED 0x40000UL
#define FLAG_XON 0x80000UL
@@ -161,9 +176,9 @@ public:
itemCmd assignFrom(itemCmd from, short chanType=-1);
bool loadItem(Item * item, uint16_t optionsFlag=SEND_PARAMETERS);
bool loadItemDef(Item * item, uint16_t optionsFlag=SEND_PARAMETERS );
bool saveItem(Item * item, uint16_t optionsFlag=SEND_PARAMETERS);
bool loadItem(Item * item, uint16_t optionsFlag=FLAG_PARAMETERS);
bool loadItemDef(Item * item, uint16_t optionsFlag=FLAG_PARAMETERS );
bool saveItem(Item * item, uint16_t optionsFlag=FLAG_PARAMETERS);
itemCmd Int(int32_t i);
itemCmd Int(uint32_t i);
@@ -209,7 +224,7 @@ public:
uint8_t getCmd();
uint8_t getArgType();
uint8_t getCmdParam();
char * toString(char * Buffer, int bufLen, int sendFlags = SEND_COMMAND | SEND_PARAMETERS, bool scale100 = false);
char * toString(char * Buffer, int bufLen, int sendFlags = FLAG_COMMAND | FLAG_PARAMETERS, bool scale100 = false);
bool isCommand();
bool isChannelCommand();

View File

@@ -39,13 +39,26 @@ e-mail anklimov@gmail.com
Syslog udpSyslog(udpSyslogClient, SYSLOG_PROTO_BSD);
static char syslogDeviceHostname[16];
Streamlog debugSerial(&debugSerialPort,LOG_DEBUG,&udpSyslog);
Streamlog errorSerial(&debugSerialPort,LOG_ERROR,&udpSyslog,ledRED);
Streamlog infoSerial (&debugSerialPort,LOG_INFO,&udpSyslog);
#if defined(debugSerialPort) && !defined(NOSERIAL)
Streamlog debugSerial(&debugSerialPort,LOG_DEBUG,&udpSyslog);
Streamlog errorSerial(&debugSerialPort,LOG_ERROR,&udpSyslog,ledRED);
Streamlog infoSerial (&debugSerialPort,LOG_INFO,&udpSyslog);
#else
Streamlog debugSerial(NULL,LOG_DEBUG,&udpSyslog);
Streamlog errorSerial(NULL,LOG_ERROR,&udpSyslog,ledRED);
Streamlog infoSerial (NULL,LOG_INFO,&udpSyslog);
#endif
#else
Streamlog debugSerial(&debugSerialPort,LOG_DEBUG);
Streamlog errorSerial(&debugSerialPort,LOG_ERROR, ledRED);
Streamlog infoSerial (&debugSerialPort,LOG_INFO);
#if defined(debugSerialPort) && !defined(NOSERIAL)
Streamlog debugSerial(&debugSerialPort,LOG_DEBUG);
Streamlog errorSerial(&debugSerialPort,LOG_ERROR, ledRED);
Streamlog infoSerial (&debugSerialPort,LOG_INFO);
#else
Streamlog debugSerial(NULL,LOG_DEBUG);
Streamlog errorSerial(NULL,LOG_ERROR, ledRED);
Streamlog infoSerial (NULL,LOG_INFO);
#endif
#endif
flashStream sysConfStream;
@@ -126,6 +139,7 @@ bool owReady = false;
bool configOk = false; // At least once connected to MQTT
bool configLoaded = false;
bool initializedListeners = false;
uint8_t DHCP_failures = 0;
volatile int8_t ethernetIdleCount =0;
volatile int8_t configLocked = 0;
@@ -247,9 +261,9 @@ uint16_t httpHandler(Client& client, String request, uint8_t method, long conten
ArduinoOTA.sendHttpResponse(client,301,false); // Send only HTTP header, no close socket
client.println(
#ifdef CORS
#ifdef REDIRECTION_URL
//Redirect to cloud PWA application
String(F("Location: " CORS "/pwa"))
String(F("Location: " REDIRECTION_URL))
#else
String(F("Location: /index.html"))
#endif
@@ -276,7 +290,7 @@ uint16_t httpHandler(Client& client, String request, uint8_t method, long conten
if (!item.isValid() || !item.Ctrl((char*) body.c_str())) return 400;
itemCmd ic;
ic.loadItem(&item,SEND_COMMAND|SEND_PARAMETERS);
ic.loadItem(&item,FLAG_COMMAND|FLAG_PARAMETERS);
char buf[32];
response=ic.toString(buf, sizeof(buf));
return 200 | HTTP_TEXT_PLAIN;
@@ -292,7 +306,7 @@ uint16_t httpHandler(Client& client, String request, uint8_t method, long conten
{if (item.isActive()) item.setCmd(CMD_ON); else item.setCmd(CMD_OFF);}
itemCmd ic;
ic.loadItem(&item,SEND_COMMAND|SEND_PARAMETERS);
ic.loadItem(&item,FLAG_COMMAND|FLAG_PARAMETERS);
char buf[32];
response=ic.toString(buf, sizeof(buf));
@@ -400,12 +414,11 @@ if (lanStatus == RETAINING_COLLECTING)
{
if (mqttClient.isRetained())
{
pfxlen=inTopic(topic,T_BCST);
if (!pfxlen) pfxlen = inTopic(topic,T_DEV);
if (!pfxlen) return; // Not command topic ever
//itemName=topic+pfxlen;
//pfxlen=inTopic(topic,T_BCST); //Dont delete bcast topics (just skip on restore retaining)
//if (!pfxlen) pfxlen = inTopic(topic,T_DEV);
pfxlen = inTopic(topic,T_DEV);
if (!pfxlen) return; // Not command topic
if (strrchr(topic,'$')) return;
//if (itemName[0]=='$') return;// -6; //Skipping homie stuff
debugSerial<<F("CleanUp retained topic ")<<topic<<endl;
mqttClient.deleteTopic(topic);
}
@@ -585,6 +598,7 @@ lan_status lanLoop() {
if (isTimeOver(WiFiAwaitingTime,millis(),WIFI_TIMEOUT))
{
errorSerial<<F("\nProblem with WiFi!");
WiFi.reconnect();
return lanStatus = DO_REINIT;
}
#else
@@ -664,6 +678,8 @@ lan_status lanLoop() {
setTopic(buf,sizeof(buf),T_OUT);
strncat(buf, "+/+/#", sizeof(buf)); // Subscribing only on separated command/parameters topics
mqttClient.unsubscribe(buf);
onMQTTConnect();
lanStatus = OPERATION;//3;
infoSerial<<F("Accepting commands...\n");
@@ -695,6 +711,19 @@ lan_status lanLoop() {
if (mqttClient.connected()) mqttClient.disconnect();
timerLanCheckTime = millis();// + 5000;
lanStatus = RECONNECT;
/*
#if defined(WIFI_ENABLE)
if (WiFi.status() != WL_CONNECTED)
{
infoSerial<<"Reconnecting WiFi"<<endl;
lanStatus = INITIAL_STATE;
WiFi.disconnect();
WiFi.reconnect();
}
#endif
*/
break;
case RECONNECT:
@@ -734,7 +763,8 @@ lan_status lanLoop() {
wdt_dis();
if (lanStatus >= HAVE_IP_ADDRESS)
{
int etherStatus = Ethernet.maintain();
int etherStatus = 0;
if (!DHCP_failures) etherStatus = Ethernet.maintain();
#ifndef Wiz5500
#define NO_LINK 5
@@ -922,6 +952,7 @@ void ip_ready_config_loaded_connecting_to_broker() {
if (mqttClient.connected())
{
//mqttClient.setKeepAlive(10);
lanStatus = RETAINING_COLLECTING;
return;
}
@@ -999,10 +1030,10 @@ void ip_ready_config_loaded_connecting_to_broker() {
setTopic(buf,sizeof(buf),T_DEV);
strncat(buf, "#", sizeof(buf));
debugSerialPort.println(buf);
debugSerial.println(buf);
mqttClient.subscribe(buf);
onMQTTConnect();
//onMQTTConnect();
// if (_once) {DMXput(); _once=0;}
lanStatus = RETAINING_COLLECTING;//4;
timerLanCheckTime = millis();// + 5000;
@@ -1079,7 +1110,11 @@ if (WiFi.status() == WL_CONNECTED) {
IPAddress ip, dns, gw, mask;
int res = 1;
infoSerial<<F("Starting lan")<<endl;
if (sysConf.getIP(ip)) {
bool loadAddressRes = sysConf.getIP(ip);
if ( loadAddressRes &&
(!sysConf.getDHCPfallback() || (DHCP_failures >= DHCP_ATTEMPTS_FALLBACK))
)
{
infoSerial<<F("Loaded from flash IP:");
printIPAddress(ip);
if (sysConf.getDNS(dns)) {
@@ -1113,6 +1148,7 @@ if (WiFi.status() == WL_CONNECTED) {
if (res == 0) {
errorSerial<<F("Failed to configure Ethernet using DHCP. You can set ip manually!")<<F("'ip [ip[,dns[,gw[,subnet]]]]' - set static IP\n");
DHCP_failures++;
lanStatus = DO_REINIT;//-10;
//timerLanCheckTime = millis();// + DHCP_RETRY_INTERVAL;
#ifdef RESET_PIN
@@ -1120,8 +1156,25 @@ if (WiFi.status() == WL_CONNECTED) {
#endif
} else {
infoSerial<<F("Got IP address:");
printIPAddress(Ethernet.localIP());
ip=Ethernet.localIP();
printIPAddress(ip);
infoSerial<<endl;
sysConf.setIP(ip);
dns=Ethernet.dnsServerIP();
sysConf.setDNS(dns);
gw=Ethernet.gatewayIP();
sysConf.setGW(gw);
mask=Ethernet.subnetMask();
sysConf.setMask(mask);
sysConf.setDHCPfallback(true);
DHCP_failures = 0;
lanStatus = HAVE_IP_ADDRESS;
}
}//DHCP
@@ -1363,8 +1416,8 @@ setupSyslog();
switch (it.itemType) {
case CH_THERMO:
if (cmd<1) it.setCmd(CMD_OFF);
it.setFlag(SEND_COMMAND);
if (it.itemVal) it.setFlag(SEND_PARAMETERS);
it.setFlag(FLAG_COMMAND);
if (it.itemVal) it.setFlag(FLAG_PARAMETERS);
pinMode(pin, OUTPUT);
digitalWrite(pin, false); //Initially, all thermostates are LOW (OFF for electho heaters, open for water NO)
debugSerial<<F("Thermo:")<<pin<<F("=LOW")<<F(";");
@@ -1457,6 +1510,7 @@ int loadConfigFromEEPROM()
#endif
if (sysConfStream.peek() == '{') {
debugSerial<<F("Trying Load from EEPROM")<<endl;
aJsonStream as = aJsonStream(&sysConfStream);
cleanConf();
root = aJson.parse(&as);
@@ -1497,35 +1551,13 @@ if (arg_cnt>1)
#else
sysConfStream.open(FN_CONFIG_JSON,'w');
#endif
#if defined(__SAM3X8E__)
long configBufSize = min(MAX_JSON_CONF_SIZE,freeRam()-1024);
debugSerial<<"Allocate "<<configBufSize<<" bytes for buffer"<<endl;
char* outBuf = (char*) malloc(configBufSize); /* XXX: Dynamic size. */
if (!outBuf)
{
sysConfStream.close();
errorSerial<<"Can't allocate RAM"<<endl;
return 500;
}
infoSerial<<F("Saving config to EEPROM..")<<endl;
aJsonStringStream stringStream(NULL, outBuf, configBufSize);
aJson.print(root, &stringStream);
int len = strlen(outBuf);
outBuf[len++]= EOFchar;
size_t res = sysConfStream.write((byte*) outBuf,len);
free (outBuf);
infoSerial<<res<< F(" bytes from ")<<len<<F(" are saved to EEPROM")<<endl;
#else
aJsonStream jsonEEPROMStream = aJsonStream(&sysConfStream);
infoSerial<<F("Saving config to EEPROM..");
aJson.print(root, &jsonEEPROMStream);
//sysConfStream.putEOF();
//sysConfStream.flush();
sysConfStream.close();
infoSerial<<F("Saved to EEPROM")<<endl;
#endif
//#endif
sysConf.saveETAG();
return 200;
}
@@ -1601,6 +1633,7 @@ int cmdFunctionIp(int arg_cnt, char **args)
printIPAddress(current_mask); */
//}
infoSerial<<F("Saved\n");
sysConf.setDHCPfallback(false);
return 200;
}
@@ -1750,7 +1783,7 @@ if (!sysConf.getServer(configServer,sizeof(configServer)))
// FILE is the return STREAM type of the HTTPClient
configStream = hclient.getURI(URI,NULL,get_header);
responseStatusCode = hclient.getLastReturnCode();
//debugSerial<<F("http retcode ")<<responseStatusCode<<endl;delay(100);
debugSerial<<F("http retcode ")<<responseStatusCode<<endl;delay(100);
//wdt_en();
if (configStream != NULL) {
@@ -1993,13 +2026,113 @@ int16_t attachTimer(double microseconds, timerCallback callback, const char* Tim
}
#endif
#if defined(WIFI_ENABLE)
#if defined (ESP32)
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
{
debugSerial.printf("[WiFi-event] event: %d\n", event);
switch (event) {
case SYSTEM_EVENT_WIFI_READY:
debugSerial.println("WiFi interface ready");
break;
case SYSTEM_EVENT_SCAN_DONE:
debugSerial.println("Completed scan for access points");
break;
case SYSTEM_EVENT_STA_START:
debugSerial.println("WiFi client started");
break;
case SYSTEM_EVENT_STA_STOP:
debugSerial.println("WiFi client stopped");
//changeState(MYSTATE_OFFLINE);
break;
case SYSTEM_EVENT_STA_CONNECTED:
debugSerial.println("Connected to access point");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
debugSerial.println("Disconnected from WiFi access point");
WiFi.reconnect();
break;
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
debugSerial.println("Authentication mode of access point has changed");
break;
case SYSTEM_EVENT_STA_GOT_IP:
debugSerial.print("Obtained IP address: ");
//Serial.println(WiFi.localIP());
//Serial.println("WiFi connected");
//Serial.print("IP address: ");
debugSerial.println(IPAddress(info.got_ip.ip_info.ip.addr));
//changeState(MYSTATE_ONLINE);
break;
case SYSTEM_EVENT_STA_LOST_IP:
debugSerial.println("Lost IP address and IP address is reset to 0");
//changeState(MYSTATE_OFFLINE);
break;
case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
debugSerial.println("WiFi Protected Setup (WPS): succeeded in enrollee mode");
break;
case SYSTEM_EVENT_STA_WPS_ER_FAILED:
debugSerial.println("WiFi Protected Setup (WPS): failed in enrollee mode");
break;
case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT:
debugSerial.println("WiFi Protected Setup (WPS): timeout in enrollee mode");
break;
case SYSTEM_EVENT_STA_WPS_ER_PIN:
debugSerial.println("WiFi Protected Setup (WPS): pin code in enrollee mode");
break;
case SYSTEM_EVENT_AP_START:
debugSerial.println("WiFi access point started");
break;
case SYSTEM_EVENT_AP_STOP:
debugSerial.println("WiFi access point stopped");
break;
case SYSTEM_EVENT_AP_STACONNECTED:
debugSerial.println("Client connected");
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
debugSerial.println("Client disconnected");
break;
case SYSTEM_EVENT_AP_STAIPASSIGNED:
debugSerial.println("Assigned IP address to client");
break;
case SYSTEM_EVENT_AP_PROBEREQRECVED:
debugSerial.println("Received probe request");
break;
case SYSTEM_EVENT_GOT_IP6:
debugSerial.println("IPv6 is preferred");
break;
case SYSTEM_EVENT_ETH_START:
debugSerial.println("Ethernet started");
break;
case SYSTEM_EVENT_ETH_STOP:
debugSerial.println("Ethernet stopped");
break;
case SYSTEM_EVENT_ETH_CONNECTED:
debugSerial.println("Ethernet connected");
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
debugSerial.println("Ethernet disconnected");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
debugSerial.println("Obtained IP address");
break;
default: break;
}
}
#endif
#endif
void setup_main() {
#if (SERIAL_BAUD)
debugSerialPort.begin(SERIAL_BAUD);
#if defined(debugSerialPort) && !defined(NOSERIAL)
debugSerialPort.begin(SERIAL_BAUD);
#endif
#else
#if not defined (__SAM3X8E__)
#if not defined (__SAM3X8E__) && defined (debugSerialPort) && !defined(NOSERIAL)
debugSerialPort.begin();
#endif
delay(1000);
@@ -2018,11 +2151,15 @@ void setup_main() {
if(SPIFFS.begin())
#endif
{
#if defined(debugSerialPort) && !defined(NOSERIAL)
debugSerialPort.println("SPIFFS Initialize....ok");
#endif
}
else
{
#if defined(debugSerialPort) && !defined(NOSERIAL)
debugSerialPort.println("SPIFFS Initialization...failed");
#endif
}
#endif
#else
@@ -2037,7 +2174,9 @@ void setup_main() {
if (!sysConf.isValidSysConf())
{
#if defined(debugSerialPort) && !defined(NOSERIAL)
debugSerialPort.println(F("No valid EEPROM data. Initializing."));
#endif
sysConf.clear();
}
// scan_i2c_bus();
@@ -2072,7 +2211,7 @@ void setup_main() {
#else
pinMode(TXEnablePin, OUTPUT);
#endif
modbusSerial.begin(MODBUS_SERIAL_BAUD,dimPar);
modbusSerial.begin(MODBUS_SERIAL_BAUD,MODBUS_SERIAL_PARAM);
node.idle(&modbusIdle);
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
@@ -2090,6 +2229,11 @@ void setup_main() {
//#ifdef _artnet
// artnetSetup();
//#endif
#if defined(WIFI_ENABLE)
#if defined (ESP32)
WiFi.onEvent(WiFiEvent);
#endif
#endif
#if defined(WIFI_ENABLE) and not defined(WIFI_MANAGER_DISABLE)
// WiFiManager wifiManager;
@@ -2159,11 +2303,17 @@ infoSerial<<F("\nFirmware MAC Address " QUOTE(CUSTOM_FIRMWARE_MAC));
#endif
#ifdef _modbus
infoSerial<<F("\n(+)MODBUS " QUOTE(MODBUS_DIMMER_PARAM) " at " QUOTE(modbusSerial) " speed:" QUOTE(MODBUS_SERIAL_BAUD));
infoSerial<<F("\n(+)MODBUS " QUOTE(MODBUS_SERIAL_PARAM) " at " QUOTE(modbusSerial) " speed:" QUOTE(MODBUS_SERIAL_BAUD));
#else
infoSerial<<F("\n(-)MODBUS");
#endif
#ifdef IPMODBUS
infoSerial<<F("\n(+)IPMODBUS ");// QUOTE(MODBUS_TCP_PARAM) " at " QUOTE(modbusSerial) " speed:" QUOTE(MODBUS_TCP_BAUD));
#else
infoSerial<<F("\n(-)IPMODBUS");
#endif
#ifndef OWIRE_DISABLE
infoSerial<<F("\n(+)OWIRE");
#ifdef USE_1W_PIN
@@ -2282,9 +2432,17 @@ infoSerial<<F("\n(-)MULTIVENT");
infoSerial<<F("\n(+)HUMIDIFIER");
#endif
#ifdef NOSERIAL
infoSerial<<F("\nNOSERIAL");
#endif
#ifdef ELEVATOR_ENABLE
infoSerial<<F("\n(+)ELEVATOR");
#endif
//#ifdef IPMODBUS
//infoSerial<<F("\n(+)IPMODBUS");
//#endif
infoSerial<<endl;
// WDT_Disable( WDT ) ;
@@ -2310,18 +2468,23 @@ void publishStat(){
uint32_t ut = millis()/1000UL;
if (!mqttClient.connected() || ethernetIdleCount) return;
setTopic(topic,sizeof(topic),T_DEV);
strncat_P(topic, stats_P, sizeof(topic));
strncat_P(topic, stats_P, sizeof(topic)-1);
strncat(topic, "/", sizeof(topic));
strncat_P(topic, freeheap_P, sizeof(topic));
strncat_P(topic, freeheap_P, sizeof(topic)-1);
printUlongValueToStr(intbuf, fr);
mqttClient.publish(topic,intbuf,true);
setTopic(topic,sizeof(topic),T_DEV);
strncat_P(topic, stats_P, sizeof(topic));
strncat_P(topic, stats_P, sizeof(topic)-1);
strncat(topic, "/", sizeof(topic));
strncat_P(topic, uptime_P, sizeof(topic));
strncat_P(topic, uptime_P, sizeof(topic)-1);
printUlongValueToStr(intbuf, ut);
mqttClient.publish(topic,intbuf,true);
setTopic(topic,sizeof(topic),T_DEV);
strncat_P(topic, state_P, sizeof(topic)-1);
strncpy_P(intbuf, ready_P, sizeof(intbuf)-1);
mqttClient.publish(topic,intbuf,true);
}
void setupMacAddress() {

View File

@@ -317,4 +317,6 @@ void ip_ready_config_loaded_connecting_to_broker();
void printCurentLanConfig();
void onMQTTConnect();
//void printFreeRam();

View File

@@ -21,16 +21,21 @@ static bool CCS811ready = false;
int in_ccs811::Setup()
{
if (CCS811ready) {debugSerial<<F("ccs811 is already initialized")<<endl; return 0;}
if (CCS811ready) {errorSerial<<F("ccs811 is already initialized")<<endl; return 0;}
#ifdef WAK_PIN
pinMode(WAK_PIN,OUTPUT);
digitalWrite(WAK_PIN,LOW);
#endif
debugSerial.println("CCS811 Init");
infoSerial.println("CCS811 Init");
#if defined (TWI_SCL) && defined (TWI_SDA)
Wire.begin(TWI_SDA,TWI_SCL); //Inialize I2C Harware
#else
Wire.begin(); //Inialize I2C Harware
#endif
Wire.setClock(4000);
//It is recommended to check return status on .begin(), but it is not
@@ -40,7 +45,7 @@ Wire.setClock(4000);
if (returnCode != CCS811Core::SENSOR_SUCCESS)
//if (returnCode != CCS811Core::CCS811_Stat_SUCCESS)
{
Serial.print("CCS811 Init error ");
errorSerial.print("CCS811 Init error ");
//debugSerial.println(ccs811.statusString(returnCode));
printDriverError(returnCode);
return 0;
@@ -116,8 +121,8 @@ if (reg!=0xff)
// New tyle unified activities
aJsonObject *actT = aJson.getObjectItem(in->inputObj, "temp");
aJsonObject *actH = aJson.getObjectItem(in->inputObj, "hum");
executeCommand(actT,-1,itemCmd(t));
executeCommand(actH,-1,itemCmd(h));
if (!isnan(t)) executeCommand(actT,-1,itemCmd(t));
if (!isnan(t)) executeCommand(actH,-1,itemCmd(h));
publish(t,"/T");
publish(h,"/H");

View File

@@ -10,15 +10,22 @@
//#define CCS811_ADDR 0x5B //Default I2C Address
#define CCS811_ADDR 0x5A //Alternate I2C Address
#if defined (ARDUINO_ARCH_ESP8266)
#define twi_scl D1
#ifndef WAK_PIN
#define WAK_PIN D3
#endif
#if defined (ARDUINO_ARCH_ESP8266)
#if not defined (TWI_SCL) && defined (D1)
#define TWI_SCL D1
#endif
#if not defined (WAK_PIN) && defined (D3)
#define WAK_PIN D3
#endif
#if defined (TWI_SCL)
#define SCL_LOW() (GPES = (1 << TWI_SCL))
#define SCL_HIGH() (GPEC = (1 << TWI_SCL))
#define SCL_RESET
#endif
#define SCL_LOW() (GPES = (1 << twi_scl))
#define SCL_HIGH() (GPEC = (1 << twi_scl))
#define SCL_RESET
#endif
/*

View File

@@ -8,27 +8,25 @@
#include "textconst.h"
#include "main.h"
#include "config.h"
#include "streamlog.h"
extern systemConfig sysConf;
extern bool disableCMD;
#ifndef AC_Serial
#define AC_Serial Serial3
#endif
#define INTERVAL_AC_POLLING 5000L
static int driverStatus = CST_UNKNOWN;
#define AC_FAILED 15
#define AC_UNKNOWN CST_UNKNOWN
#define AC_IDLE CST_INITIALIZED
#define AC_SENDING 2
static int fresh =0;
static int power = 0;
static int swing =0;
static int lock_rem =0;
static int cur_tmp = 0;
static int set_tmp = 0;
static int fan_spd = 0;
static int mode = 0;
long prevPolling = 0;
byte inCheck = 0;
byte qstn[] = {255,255,10,0,0,0,0,0,1,1,77,1,90}; // Команда опроса
byte data[37] = {}; //Массив данных
byte on[] = {255,255,10,0,0,0,0,0,1,1,77,2,91}; // Включение кондиционера
byte off[] = {255,255,10,0,0,0,0,0,1,1,77,3,92}; // Выключение кондиционера
byte lock[] = {255,255,10,0,0,0,0,0,1,3,0,0,14}; // Блокировка пульта
@@ -39,16 +37,55 @@ const char QUIET_P[] PROGMEM = "queit";
const char SWING_P[] PROGMEM = "swing";
const char RAW_P[] PROGMEM = "raw";
void out_AC::getConfig(){
ACSerial=&AC_Serial;
if (!item) return;
if (item->getArgCount())
switch(portNum=item->getArg(0)){
case 0: ACSerial=&Serial;
break;
#if not defined (AVR) || defined (DMX_DISABLE)
case 1: ACSerial=&Serial1;
break;
#endif
#if defined (HAVE_HWSERIAL2) || defined (__SAM3X8E__) || defined (ESP32)
case 2: ACSerial=&Serial2;
break;
#endif
#if defined (HAVE_HWSERIAL3) || defined (__SAM3X8E__)
case 3: ACSerial=&Serial3;
break;
#endif
}
}
void out_AC::InsertData(byte data[], size_t size){
int fresh =0;
int swing =0;
int lock_rem =0;
int cur_tmp = 0;
int set_tmp = 0;
int fan_spd = 0;
char s_mode[10];
set_tmp = data[B_SET_TMP]+16;
if (set_tmp>40 || set_tmp<16) return;
cur_tmp = data[B_CUR_TMP];
mode = data[B_MODE];
store->mode = data[B_MODE];
fan_spd = data[B_FAN_SPD];
swing = data[B_SWING];
power = data[B_POWER];
store->power = data[B_POWER];
lock_rem = data[B_LOCK_REM];
fresh = data[B_FRESH];
/////////////////////////////////
@@ -73,15 +110,15 @@ void out_AC::InsertData(byte data[], size_t size){
}
*/
debugSerial.print ("Power=");
debugSerial.println(power);
debugSerial.print ("AC: Power=");
debugSerial.println(store->power);
if (power & 0x08)
if (store->power & 0x08)
publishTopic(item->itemArr->name, "ON", "/quiet");
else publishTopic(item->itemArr->name, "OFF" , "/quiet");
if (power & 0x02) //Compressor on
if (store->power & 0x02) //Compressor on
publishTopic(item->itemArr->name, "ON","/compressor");
else
publishTopic(item->itemArr->name, "OFF","/compressor");
@@ -124,28 +161,28 @@ void out_AC::InsertData(byte data[], size_t size){
////////////////////////////////////
s_mode[0]='\0';
if (mode == 0x00){
if (store->mode == 0x00){
strcpy_P(s_mode,AUTO_P);
}
else if (mode == 0x01){
else if (store->mode == 0x01){
strcpy_P(s_mode,COOL_P);
}
else if (mode == 0x02){
else if (store->mode == 0x02){
strcpy_P(s_mode,HEAT_P);
}
else if (mode == 0x03){
else if (store->mode == 0x03){
strcpy_P(s_mode,FAN_ONLY_P);
}
else if (mode == 0x04){
else if (store->mode == 0x04){
strcpy_P(s_mode,DRY_P);
}
else if (mode == 109){
else if (store->mode == 109){
strcpy_P(s_mode,ERROR_P);
}
publishTopic(item->itemArr->name, (long) mode, "/mode");
publishTopic(item->itemArr->name, (long) store->mode, "/mode");
if (power & 0x01)
if (store->power & 0x01)
publishTopic(item->itemArr->name, s_mode,"/cmd");
else publishTopic(item->itemArr->name, "OFF","/cmd");
@@ -177,11 +214,17 @@ byte getCRC(byte req[], size_t size){
}
void out_AC::SendData(byte req[], size_t size){
AC_Serial.write(req, size - 1);
AC_Serial.write(getCRC(req, size-1));
//AC_Serial.flush();
item->setExt(millisNZ());
debugSerial.print("AirCon<<");
if (!store || !item) return;
if (item->itemArr->subtype == AC_SENDING)
{
while (store->timestamp && !isTimeOver(store->timestamp,millis(),150)) yield();
}
ACSerial->write(req, size - 1);
ACSerial->write(getCRC(req, size-1));
//ACSerial->flush();
store->timestamp=millisNZ();
debugSerial<<F("AC: ")<<portNum<<F(" <<");
for (int i=0; i < size-1; i++)
{
if (req[i] < 10){
@@ -194,7 +237,7 @@ void out_AC::SendData(byte req[], size_t size){
}
}
debugSerial.println();
item->itemArr->subtype = AC_SENDING;
}
inline unsigned char toHex( char ch ){
@@ -206,50 +249,120 @@ inline unsigned char toHex( char ch ){
int out_AC::Setup()
{
abstractOut::Setup();
debugSerial<<F("AC Init")<<endl;
AC_Serial.begin(9600);
driverStatus = CST_INITIALIZED;
if (!item) return 0;
debugSerial<<F("AC: Init: ")<<portNum<<endl;
if (!store) store= (acPersistent *)item->setPersistent(new acPersistent);
if (!store)
{ errorSerial<<F("AC: Out of memory")<<endl;
return 0;}
memset(store->data,0,sizeof(acPersistent::data));
store->mode=0;
store->power=0;
store->inCheck=0;
store->timestamp=millisNZ();
if (!portNum)// && (g_APinDescription[0].ulPinType == PIO_PA8A_URXD))
{
pinMode(0, INPUT_PULLUP);
#if debugSerial == Serial
infoSerial<<F("AC: Serial used by AC - disabling serial logging and cmd")<<endl;
//sysConf.setSerialDebuglevel(0);
serialDebugLevel = 0;
disableCMD=true;
#endif
}
ACSerial->begin(9600);
item->itemArr->subtype = AC_IDLE;
//driverStatus = CST_INITIALIZED;
return 1;
}
int out_AC::Stop()
{
debugSerial<<F("AC De-Init")<<endl;
driverStatus = CST_UNKNOWN;
if (!item) return 0;
debugSerial<<F("AC: De-Init: ")<<portNum<<endl;
delete store;
item->setPersistent(NULL);
store = NULL;
item->itemArr->subtype = CST_UNKNOWN;
return 1;
}
int out_AC::Status()
{
return driverStatus;
if (!item) return 0;
switch (item->itemArr->subtype)
{
case AC_FAILED: return CST_FAILED;
case AC_UNKNOWN: return CST_UNKNOWN;
default:
return CST_INITIALIZED;
//return item->itemArr->subtype;
}
}
int out_AC::isActive()
{
return (power & 1);
if (!store) return 0;
return (store->power & 1);
}
int out_AC::Poll(short cause)
{
if (!store) return -1;
switch (item->itemArr->subtype)
{
case AC_FAILED: return -1;
case AC_UNKNOWN: return -1;
case AC_SENDING:
{
if (store->timestamp && isTimeOver(store->timestamp,millis(),150))
{
item->itemArr->subtype = AC_IDLE;
store->timestamp=millisNZ();
}
}
}
if (cause!=POLLING_SLOW) return false;
if (isTimeOver(prevPolling,millis(),INTERVAL_AC_POLLING)) {
prevPolling = millisNZ();
debugSerial.println(F("Polling"));
if ((item->itemArr->subtype == AC_IDLE) && isTimeOver(store->timestamp,millis(),INTERVAL_AC_POLLING))
{
debugSerial.println(F("AC: Polling"));
SendData(qstn, sizeof(qstn)/sizeof(byte)); //Опрос кондиционера
}
if(AC_Serial.available() >= 37){ //was 0
AC_Serial.readBytes(data, 37);
while(AC_Serial.available()){
if(ACSerial->available() >= 37){ //was 0
ACSerial->readBytes(store->data, 37);
while(ACSerial->available()){
delay(2);
AC_Serial.read();
ACSerial->read();
}
if (data[36] != inCheck){
inCheck = data[36];
InsertData(data, 37);
debugSerial<<F("AC: ")<<portNum<<F(" >> ");
for (int i=0; i < 37-1; i++)
{
if (store->data[i] < 10){
debugSerial.print("0");
debugSerial.print(store->data[i], HEX);
}
else
{
debugSerial.print(store->data[i], HEX);
}
}
if (store->data[36] != store->inCheck){
store->inCheck = store->data[36];
InsertData(store->data, 37);
debugSerial<<F("AC: OK");
}
debugSerial.println();
}
return true;
};
@@ -273,14 +386,16 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
switch(suffixCode)
{
case S_SET:
set_tmp = cmd.getInt();
{
byte set_tmp = cmd.getInt();
if (set_tmp >= 16 && set_tmp <= 40)
{
//if (set_tmp>40 || set_tmp<16) set_temp=21;
data[B_SET_TMP] = set_tmp -16;
store->data[B_SET_TMP] = set_tmp -16;
publishTopic(item->itemArr->name,(long) set_tmp,"/set");
}
else return -1;
else return -1;
}
break;
case S_CMD:
@@ -289,52 +404,52 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
{
case CMD_ON:
case CMD_XON:
data[B_POWER] = power;
data[B_POWER] |= 1;
store->data[B_POWER] = store->power;
store->data[B_POWER] |= 1;
SendData(on, sizeof(on)/sizeof(byte));
// publishTopic(item->itemArr->name,"ON","/cmd");
return 1;
break;
case CMD_OFF:
case CMD_HALT:
data[B_POWER] = power;
data[B_POWER] &= ~1;
store->data[B_POWER] = store->power;
store->data[B_POWER] &= ~1;
SendData(off, sizeof(off)/sizeof(byte));
// publishTopic(item->itemArr->name,"OFF","/cmd");
return 1;
break;
case CMD_AUTO:
data[B_MODE] = 0;
data[B_POWER] = power;
data[B_POWER] |= 1;
store->data[B_MODE] = 0;
store->data[B_POWER] = store->power;
store->data[B_POWER] |= 1;
// strcpy_P(s_mode,AUTO_P);
break;
case CMD_COOL:
data[B_MODE] = 1;
data[B_POWER] = power;
data[B_POWER] |= 1;
store->data[B_MODE] = 1;
store->data[B_POWER] = store->power;
store->data[B_POWER] |= 1;
// strcpy_P(s_mode,COOL_P);
break;
case CMD_HEAT:
data[B_MODE] = 2;
data[B_POWER] = power;
data[B_POWER] |= 1;
store->data[B_MODE] = 2;
store->data[B_POWER] = store->power;
store->data[B_POWER] |= 1;
// strcpy_P(s_mode,HEAT_P);
break;
case CMD_DRY:
data[B_MODE] = 4;
data[B_POWER] = power;
data[B_POWER] |= 1;
store->data[B_MODE] = 4;
store->data[B_POWER] = store->power;
store->data[B_POWER] |= 1;
// strcpy_P(s_mode,DRY_P);
break;
case CMD_FAN:
data[B_MODE] = 3;
store->data[B_MODE] = 3;
// debugSerial<<"fan\n";
data[B_POWER] = power;
data[B_POWER] |= 1;
if (data[B_FAN_SPD] == 3)
store->data[B_POWER] = store->power;
store->data[B_POWER] |= 1;
if (store->data[B_FAN_SPD] == 3)
{
data[B_FAN_SPD] = 2; //Auto - fan speed in Ventilation mode not working
store->data[B_FAN_SPD] = 2; //Auto - fan speed in Ventilation mode not working
}
// strcpy_P(s_mode,FAN_ONLY_P);
break;
@@ -351,24 +466,24 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
switch (cmd.getCmd())
{
case CMD_AUTO:
data[B_FAN_SPD] = 3;
store->data[B_FAN_SPD] = 3;
strcpy_P(s_speed,AUTO_P);
break;
case CMD_HIGH:
data[B_FAN_SPD] = 0;
store->data[B_FAN_SPD] = 0;
strcpy_P(s_speed,HIGH_P);
break;
case CMD_MED:
data[B_FAN_SPD] = 1;
store->data[B_FAN_SPD] = 1;
strcpy_P(s_speed,MED_P);
break;
case CMD_LOW:
data[B_FAN_SPD] = 2;
store->data[B_FAN_SPD] = 2;
strcpy_P(s_speed,LOW_P);
break;
default:
//if (n) data[B_FAN_SPD] = Parameters[0];
data[B_FAN_SPD] = cmd.getInt();
store->data[B_FAN_SPD] = cmd.getInt();
//TODO - mapping digits to speed
}
publishTopic(item->itemArr->name,s_speed,"/fan");
@@ -376,17 +491,17 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
case S_MODE:
//data[B_MODE] = Parameters[0];
data[B_MODE] = cmd.getInt();
store->data[B_MODE] = cmd.getInt();
break;
case S_LOCK:
switch (cmd.getCmd())
{
case CMD_ON:
data[B_LOCK_REM] = 80;
store->data[B_LOCK_REM] = 80;
break;
case CMD_OFF:
data[B_LOCK_REM] = 0;
store->data[B_LOCK_REM] = 0;
break;
}
break;
@@ -395,16 +510,16 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
switch (cmd.getCmd())
{
case CMD_ON:
data[B_SWING] = 3;
store->data[B_SWING] = 3;
publishTopic(item->itemArr->name,"ON","/swing");
break;
case CMD_OFF:
data[B_SWING] = 0;
store->data[B_SWING] = 0;
publishTopic(item->itemArr->name,"OFF","/swing");
break;
default:
//if (n) data[B_SWING] = Parameters[0];
data[B_SWING] = cmd.getInt();
store->data[B_SWING] = cmd.getInt();
}
break;
@@ -413,10 +528,10 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
switch (cmd.getCmd())
{
case CMD_ON:
data[B_POWER] |= 8;
store->data[B_POWER] |= 8;
break;
case CMD_OFF:
data[B_POWER] &= ~8;
store->data[B_POWER] &= ~8;
break;
}
@@ -434,8 +549,8 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
hexbyte[0] = buf[i] ;
hexbyte[1] = buf[i+1] ;
data[i/2] = (toHex(hexbyte[0]) << 4) | toHex(hexbyte[1]);
AC_Serial.write(data, 37);
AC_Serial.flush();
ACSerial->write(data, 37);
ACSerial->flush();
publishTopic("RAW", buf);
}
*/
@@ -470,16 +585,18 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
//if (strTopic == "/myhome/in/Conditioner/RAW")
data[B_CMD] = 0;
data[9] = 1;
data[10] = 77;
data[11] = 95;
AC_Serial.flush();
uint32_t ts=item->getExt();
while (ts && !isTimeOver(ts,millis(),100)) yield();
SendData(data, sizeof(data)/sizeof(byte));
store->data[B_CMD] = 0;
store->data[9] = 1;
store->data[10] = 77;
store->data[11] = 95;
///ACSerial->flush();
//uint32_t ts=item->getExt();
//while (ts && !isTimeOver(ts,millis(),100)) yield();
SendData(store->data, sizeof(store->data)/sizeof(byte));
//InsertData(data, sizeof(data)/sizeof(byte));
//AC_Serial.flush();
//ACSerial->flush();
//item->setExt(millisNZ());
return 1;
}

View File

@@ -2,6 +2,7 @@
#pragma once
#ifndef AC_DISABLE
#include <abstractout.h>
#include <item.h>
#include "itemCmd.h"
#define LEN_B 37
@@ -21,10 +22,21 @@
//#define S_RAW S_ADDITIONAL+4
extern void modbusIdle(void) ;
class acPersistent : public chPersistent {
public:
byte data[37];
byte power;
byte mode;
byte inCheck;
uint32_t timestamp;
};
class out_AC : public abstractOut {
public:
out_AC(Item * _item):abstractOut(_item){};
out_AC(Item * _item):abstractOut(_item){store = (acPersistent *) item->getPersistent(); getConfig();};
void getConfig();
int Setup() override;
int Poll(short cause) override;
int Stop() override;
@@ -33,9 +45,17 @@ public:
int getChanType() override;
int getDefaultStorageType(){return ST_FLOAT_CELSIUS;};
int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true) override;
protected:
acPersistent * store;
void InsertData(byte data[], size_t size);
void SendData(byte req[], size_t size);
uint8_t portNum;
#if defined (__SAM3X8E__)
UARTClass *ACSerial;
#else
HardwareSerial *ACSerial;
#endif
};
#endif

View File

@@ -13,8 +13,10 @@ static int driverStatus = CST_UNKNOWN;
void out_counter::getConfig()
{
if (!item) return;
impulse = item->getFloatArg(0);
period = item->getFloatArg(1)*1000.0;
impulse = item->getFloatArg(0)*TENS_BASE;
period = item->getFloatArg(1)*1000.0;
//debugSerial<<"CTR: imp:"<<impulse<<" period:"<<period<<endl;
}
int out_counter::Setup()
@@ -38,7 +40,7 @@ return driverStatus;
int out_counter::Poll(short cause)
{
if (cause==POLLING_SLOW) return 0;
if (cause==POLLING_SLOW || cause==POLLING_INT) return 0;
if (!item) return 0;
@@ -47,13 +49,20 @@ uint32_t timer = item->getExt();
if (timer && period && isTimeOver(timer,millis(),period))
{
item->setExt(millisNZ());
itemCmd st;
st.loadItem(item,SEND_PARAMETERS|SEND_COMMAND);
float val = st.getFloat();
st.loadItem(item,FLAG_PARAMETERS|FLAG_COMMAND);
//float val = st.getFloat();
uint32_t val = st.getTens_raw();
//short cmd = st.getCmd();
debugSerial<<"CTR: tick val:"<<val<< " + "<< impulse << endl;
val+=impulse;
st.Float(val);
//st.Float(val);
st.Tens_raw(val);
st.saveItem(item);
debugSerial<<"CTR: tick saved val:"<<val<<endl;
item->SendStatus(FLAG_PARAMETERS);
}
return 0;
@@ -82,13 +91,11 @@ case S_SET:
if (!item->getExt())
{
item->setExt(millisNZ());
//relay(true);
}
}
else
{
item->setExt(0);
}
}
return 1;
@@ -105,13 +112,11 @@ case S_CMD:
if (!item->getExt())
{
item->setExt(millisNZ());
//relay(true);
}
return 1;
case CMD_OFF:
item->setExt(0);
return 1;
default:

View File

@@ -20,7 +20,8 @@ public:
int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true) override;
protected:
float impulse;
//float impulse;
uint32_t impulse;
uint32_t period;
};
#endif

View File

@@ -0,0 +1,489 @@
//Спецификация протокола тут
//https://ftp.owen.ru/CoDeSys3/04_Library/05_3.5.11.5/02_Libraries/02_vendor_protocols/merkuriy-sistema-komand-sogl-1-2021-02-02.pdf
// Использованы фрагменты кода отсюда: https://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/arduino-mega-merkurii-2032t-rs485
#ifdef MERCURY_ENABLE
#include "modules/out_mercury.h"
#include "Arduino.h"
#include "options.h"
#include "utils.h"
#include "Streaming.h"
#include "item.h"
#include <ModbusMaster.h>
#include "main.h"
#include <HardwareSerial.h>
extern aJsonObject *modbusObj;
extern ModbusMaster node;
extern short modbusBusy;
extern void modbusIdle(void) ;
extern uint32_t mbusSlenceTimer;
bool out_Mercury::getConfig()
{
if (!store || !item || !item->itemArg || (item->itemArg->type != aJson_Array) || aJson.getArraySize(item->itemArg)<6)
{
errorSerial<<F("Mercury: config failed:")<<(bool)store<<F(",")<<(bool)item<<F(",")<<(bool)item->itemArg<<F(",")<<(item->itemArg->type != aJson_Array)<<F(",")<< (aJson.getArraySize(item->itemArg)<6)<<endl;
return false;
}
aJsonObject * delayObj=aJson.getArrayItem(item->itemArg, 5);
if (delayObj) pollingInterval = delayObj->valueint;
else pollingInterval = 10000;
return true;
}
void out_Mercury::initLine(bool full)
{
int baud;
serialParamType serialParam;
aJsonObject * serialParamObj=aJson.getArrayItem(item->itemArg, 2);
if (serialParamObj && serialParamObj->type == aJson_String) serialParam = str2SerialParam(serialParamObj->valuestring);
else serialParam = SERIAL_8N1;
aJsonObject * baudObj=aJson.getArrayItem(item->itemArg, 1);
if (baudObj && baudObj->type == aJson_Int && baudObj->valueint) baud = baudObj->valueint;
else baud = 9600;
#if defined (__SAM3X8E__)
modbusSerial.begin(baud, static_cast <USARTClass::USARTModes> (serialParam));
#elif defined (ARDUINO_ARCH_ESP8266)
modbusSerial.begin(baud, static_cast <SerialConfig>(serialParam));
#elif defined (ESP32)
if (full) modbusSerial.begin(store->baud, (serialParam),MODBUS_UART_RX_PIN,MODBUS_UART_TX_PIN);
else modbusSerial.updateBaudRate (baud); //Some terrible error in ESP32 core with uart reinit
#else
modbusSerial.begin(baud, (serialParam));
#endif
//debugSerial<<F("Mercury: ")<< baud << F(" <")<< serialParam<< F("> addr:")<<item->getArg(0)<<endl;
node.begin(item->getArg(0), modbusSerial);
}
int out_Mercury::Setup()
{
abstractOut::Setup();
if (!store) store= (mercuryPersistent *)item->setPersistent(new mercuryPersistent);
if (!store)
{ errorSerial<<F("Mercury: Out of memory")<<endl;
return 0;}
store->timestamp=millisNZ();
if (getConfig())
{
infoSerial<<F("Mercury: config loaded ")<< item->itemArr->name<<endl;
store->driverStatus = CST_INITIALIZED;
store->lastSuccessTS = 0;
initLine(true);
return 1;
}
else
{ errorSerial<<F("Mercury: config error")<<endl;
store->driverStatus = CST_FAILED;
return 0;
}
}
int out_Mercury::Stop()
{
debugSerial.println("Mercury: De-Init");
disconnectMercury();
delete store;
item->setPersistent(NULL);
store = NULL;
return 1;
}
int out_Mercury::Status()
{
if (store)
return store->driverStatus;
return CST_UNKNOWN;
}
void out_Mercury::setStatus(short status)
{
if (store) store->driverStatus=status;
}
short out_Mercury::connectMercury()
{
if (!item || !item->itemArg || modbusBusy) return RET_INTERROR;
uint8_t buffer[10];
uint8_t ret;
modbusBusy=1;
initLine();
buffer[1]=1; //Login
aJsonObject * levelObj=aJson.getArrayItem(item->itemArg, 3);
if (levelObj && levelObj->type == aJson_Int) buffer[2] = levelObj->valueint;
else errorSerial<<F("Mercury: wrong accesslevel")<<endl;
aJsonObject * passObj=aJson.getArrayItem(item->itemArg, 4);
if (passObj && passObj->type == aJson_String && (strlen (passObj->valuestring) == 6)) memcpy((char*) buffer+3,passObj->valuestring,6);
else if (passObj && passObj->type == aJson_Array && (aJson.getArraySize (passObj) == 6))
{
//debugSerial<<F("Mercury: Pass :");
for(short i=0;i<6;i++)
{
aJsonObject * digitObj=aJson.getArrayItem(passObj,i);
if (digitObj && digitObj->type==aJson_Int)
{
buffer[3+i]=digitObj->valueint;
//debugSerial<< digitObj->valueint<< F(",");
}
}
debugSerial<<endl;
}
else errorSerial<<F("Mercury: passwort must be ether String[6] or Array[6]")<<endl;
debugSerial<<F("Mercury: Connect ")<< item->itemArr->name<<F(" level:")<< buffer[2] ;//<< F(" pass:")<< passObj->valuestring;
ret=node.ModbusRawTransaction(buffer,9,4);
modbusBusy=0;
if (!ret) ret = buffer[1];
debugSerial<<F(" res:")<< ret << endl;
mbusSlenceTimer = millisNZ();
return ret;
}
short out_Mercury::disconnectMercury()
{
if (!item || !item->itemArg || modbusBusy) return RET_INTERROR;
uint8_t buffer[4];
uint8_t ret;
modbusBusy=1;
initLine();
buffer[1]=2; //Close
ret=node.ModbusRawTransaction(buffer,2,4);
modbusBusy=0;
if (!ret) ret = buffer[1];
debugSerial<<F("Mercury: Disconnect ")<< item->itemArr->name<<F(" res:")<< ret << endl;
mbusSlenceTimer = millisNZ();
return ret;
}
///////////////////// команды//////////////////////////////////////////////////////
//byte testConnect[] = { 0x00, 0x00 }; //тест связи
//byte Sn[] = { 0x00, 0x08, 0x05 }; //запрос сетевого адреса
//byte Open[] = { 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; //открыть канал с паролеи
//byte Close[] = { 0x00, 0x02 }; // закрыть канал (а то ждать 4 минуты)
//byte activPower[] = { 0x00, 0x05, 0x00, 0x00 }; //суммарная энергия прямая + обратная + активная + реактивная
//byte ind[] = { 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x1F, 0x00, 0x1F, 0x00 }; //маска индикации работает только для автоматического режима
//byte Angle[] = { 0x00, 0x08, 0x16, 0x51 }; // углы между фазами 1и2, 1и3, 2и3
////////////////////////подпрограмма чтения показаний счётчика////////////////////////////////////
#define M_BEGIN_YESTERDAY 0xD0 // показания на начало вчерашних суток
#define M_BEGIN_TODAY 0x21 // показания на начало сегодняшних суток
#define M_NOW 0x00 // показания на сейчас
//2.5.17 Запросы на чтение массивов регистров накопленной энергии
short out_Mercury::getCounters(byte when, String topic, int divisor)
{
if (!item || !item->itemArg || modbusBusy) return RET_INTERROR;
modbusBusy=1;
initLine();
uint8_t response[19]{}; //1+4+4+4+4+2
response[1]=0x05;
response[2]=when; // показания на начало вчерашних суток 0xD0
uint8_t ret=node.ModbusRawTransaction(response, 4 , sizeof(response));
if (!ret)
{
unsigned long r = 0;
r |= (unsigned long)response[2]<<24;
r |= (unsigned long)response[1]<<16;
r |= (unsigned long)response[4]<<8;
r |= (unsigned long)response[3];
publishTopic(item->itemArr->name, (float) r/1000,(topic+"/Active").c_str());
//Обратную (5-8) пропускаем
r = 0;
r |= (unsigned long)response[10]<<24;
r |= (unsigned long)response[9]<<16;
r |= (unsigned long)response[12]<<8;
r |= (unsigned long)response[11];
publishTopic(item->itemArr->name, (float) r/1000,(topic+"/Reactive").c_str());
//Обратную (13-16) пропускаем
};
debugSerial<<F("Mercury: getCounters ")<< item->itemArr->name << F(" res:")<< ret << endl;
modbusBusy=0;
mbusSlenceTimer = millisNZ();
return ret;
}
/////////////////////////углы, напряжения токи по фазам//////////////////////////////////////////////////
#define VOLTAGE 0x11 //0x11 напряжения пофазно, 100делитель
#define CURRENT 0x21 //0x21 токи пофазно
#define ANGLES 0x51 //0x51 углы между напряжениями фаз, 100делитель
#define M_COSF 0x31
#define M_ANGLE_DEF 0x30
#define M_PWR 0x00
short out_Mercury::getCurrentVal12(byte param, String topic, int divisor)
{
if (!item || !item->itemArg || modbusBusy) return RET_INTERROR;
modbusBusy=1;
initLine();
uint8_t response[12]{};
response[1]=0x08; //2.6 Запросы на чтение параметров
response[2]=0x16; //2.6.16 Чтение вспомогательных параметров: мгновенной активной,реактивной, полной мощности,
// фазных и линейных, напряжений,тока, коэффициента мощности,частоты, небаланса
// Ответ 12 (9) двоичных байт. Два старших разряда старшего байта указывают положение вектора полной мощности и
// должны маскироваться (см. п. 1.5)
response[3]=param;
uint8_t ret=node.ModbusRawTransaction(response, 4 , sizeof(response));
if (!ret)
{
long r = 0;
r |= (long)response[1]<<16;
r |= (long)response[3]<<8;
r |= (long)response[2];
publishTopic(item->itemArr->name, (float) r/divisor,(topic+"/A").c_str());
r = 0;
r |= (long)response[4]<<16;
r |= (long)response[6]<<8;
r |= (long)response[5];
publishTopic(item->itemArr->name, (float) r/divisor,(topic+"/B").c_str());
r=0;
r |= (long)response[7]<<16;
r |= (long)response[9]<<8;
r |= (long)response[8];
publishTopic(item->itemArr->name, (float) r/divisor,(topic+"/C").c_str());
}
debugSerial<<F("Mercury: getCurrentVal12 ")<< item->itemArr->name << F(" res:")<< ret << endl;
modbusBusy=0;
mbusSlenceTimer = millisNZ();
return ret;
}
//cosSN(); //0x31 углы между напряжениями фазы и током COSf
/////////////////////////COSf по фазам//////////////////////////////////////////////////
short out_Mercury::getCurrentVal15(byte param, String topic, int divisor)
{
if (!item || !item->itemArg || modbusBusy) return RET_INTERROR;
modbusBusy=1;
initLine();
uint8_t response[15]{};
response[1]=0x08;
response[2]=0x16;
response[3]=param;
uint8_t ret=node.ModbusRawTransaction(response, 4 , sizeof(response));
if (!ret)
{
long r = 0;
r |= (long)response[1]<<16;
r |= (long)response[3]<<8;
r |= (long)response[2];
publishTopic(item->itemArr->name, (float) r/divisor,(topic+"/sum").c_str());
r = 0;
r |= (long)response[4]<<16;
r |= (long)response[6]<<8;
r |= (long)response[5];
publishTopic(item->itemArr->name, (float) r/divisor,(topic+"/A").c_str());
r = 0;
r |= (long)response[7]<<16;
r |= (long)response[9]<<8;
r |= (long)response[8];
publishTopic(item->itemArr->name, (float) r/divisor,(topic+"/B").c_str());
r=0;
r |= (long)response[10]<<16;
r |= (long)response[12]<<8;
r |= (long)response[11];
publishTopic(item->itemArr->name, (float) r/divisor,(topic+"/C").c_str());
}
debugSerial<<F("Mercury: getCurrentVal15 ")<< item->itemArr->name << F(" res:")<< ret << endl;
modbusBusy=0;
mbusSlenceTimer = millisNZ();
return ret;
}
int out_Mercury::Poll(short cause)
{
//bool lineInitialized = false;
if (cause==POLLING_SLOW) return 0;
if (modbusBusy || ( mbusSlenceTimer && !isTimeOver(mbusSlenceTimer,millis(),100))) return 0;
if (!getConfig()) return 0;
switch (Status())
{
case CST_INITIALIZED:
if (isTimeOver(store->timestamp,millis(),10000UL)) setStatus(M_CONNECTING);
break;
case M_CONNECTING:
switch (connectMercury())
{
case RET_SUCCESS: setStatus(M_CONNECTED);
store->lastSuccessTS=millisNZ();
break;
case RET_NOT_CONNECTED: setStatus(CST_FAILED);
break;
default:
setStatus(CST_INITIALIZED);
}
break;
case M_CONNECTED:
if (isTimeOver(store->lastSuccessTS,millis(),240000UL)) setStatus(CST_INITIALIZED);
if (isTimeOver(store->timestamp,millis(),pollingInterval)) setStatus(M_POLLING1);
break;
case M_POLLING1:
switch (getCurrentVal12(VOLTAGE,"/voltage",100))
{
case RET_SUCCESS: setStatus(M_POLLING2);
store->timestamp=millisNZ();
store->lastSuccessTS=millisNZ();
break;
case RET_NOT_CONNECTED: setStatus(M_CONNECTING);
break;
default:
setStatus(CST_INITIALIZED);
}
break;
case M_POLLING2:
switch (getCurrentVal12(CURRENT,"/current",1000))
{
case RET_SUCCESS: setStatus(M_POLLING3);
store->timestamp=millisNZ();
store->lastSuccessTS=millisNZ();
break;
case RET_NOT_CONNECTED: setStatus(M_CONNECTING);
break;
default:
setStatus(CST_INITIALIZED);
}
break;
case M_POLLING3:
switch (getCurrentVal12(ANGLES,"/angles",100))
{
case RET_SUCCESS: setStatus(M_POLLING4);
store->timestamp=millisNZ();
store->lastSuccessTS=millisNZ();
break;
case RET_NOT_CONNECTED: setStatus(M_CONNECTING);
break;
default:
setStatus(CST_INITIALIZED);
}
break;
case M_POLLING4:
switch (getCounters(M_NOW,"/counters",1000))
{
case RET_SUCCESS: setStatus(M_POLLING5);
store->timestamp=millisNZ();
store->lastSuccessTS=millisNZ();
break;
case RET_NOT_CONNECTED: setStatus(M_CONNECTING);
break;
default:
setStatus(CST_INITIALIZED);
}
break;
case M_POLLING5:
switch (getCurrentVal12(M_PWR+1,"/power",100))
{
case RET_SUCCESS: setStatus(M_POLLING6);
store->timestamp=millisNZ();
store->lastSuccessTS=millisNZ();
break;
case RET_NOT_CONNECTED: setStatus(M_CONNECTING);
break;
default:
setStatus(CST_INITIALIZED);
}
break;
case M_POLLING6:
switch (getCurrentVal12(M_COSF,"/cosf",1000))
{
case RET_SUCCESS: setStatus(M_CONNECTED);
store->timestamp=millisNZ();
store->lastSuccessTS=millisNZ();
break;
case RET_NOT_CONNECTED: setStatus(M_CONNECTING);
break;
default:
setStatus(CST_INITIALIZED);
}
break;
}
return pollingInterval;
};
int out_Mercury::getChanType()
{
return CH_MBUS;
}
//!Control unified item
int out_Mercury::Ctrl(itemCmd cmd, char* subItem, bool toExecute)
{
if (!store) return -1;
int suffixCode = cmd.getSuffix();
int res = -1;
return res;
}
#endif

View File

@@ -0,0 +1,69 @@
#pragma once
#include "options.h"
#ifdef MERCURY_ENABLE
#include <abstractout.h>
#include <item.h>
#include "itemCmd.h"
#include <utils.h>
#include <Arduino.h>
class mercuryPersistent : public chPersistent {
public:
int8_t driverStatus;
uint32_t timestamp;
uint32_t lastSuccessTS;
};
#define MB_NEED_SEND 8
#define MB_SEND_ERROR 4
#define MB_SEND_ATTEMPTS 3
#define M_CONNECTING 10
#define M_CONNECTED 11
#define M_POLLING1 12
#define M_POLLING2 13
#define M_POLLING3 14
#define M_POLLING4 15
#define M_POLLING5 16
#define M_POLLING6 17
#define M_POLLING7 18
#define M_POLLING8 19
#define RET_SUCCESS 0
#define RET_INVALID_PARAM 1
#define RET_INTERROR 2
#define RET_ACCESS_LEVEL 3
#define RET_RTC_ERR 4
#define RET_NOT_CONNECTED 3
class out_Mercury : public abstractOut {
public:
out_Mercury(Item * _item):abstractOut(_item){store = (mercuryPersistent *) item->getPersistent();};
int Setup() override;
int Poll(short cause) override;
int Stop() override;
int Status() override;
int getChanType() override;
int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true) override;
int getDefaultStorageType(){return ST_INT32;};
protected:
mercuryPersistent * store;
uint16_t pollingInterval;
bool getConfig();
void initLine(bool full = false);
void setStatus(short);
short connectMercury();
short disconnectMercury();
short getCurrentVal12(byte param, String topic,int divisor=1);
short getCurrentVal15(byte param, String topic,int divisor=1);
short getCounters (byte when, String topic,int divisor=1);
};
#endif

View File

@@ -15,6 +15,7 @@ extern aJsonObject *modbusObj;
extern ModbusMaster node;
extern short modbusBusy;
extern void modbusIdle(void) ;
uint32_t mbusSlenceTimer = 0;
struct reg_t
{
@@ -96,6 +97,7 @@ serialParamType str2SerialParam(char * str)
return static_cast<serialParamType> (SERIAL_8N1);
}
*/
uint16_t swap (uint16_t x) {return ((x & 0xff) << 8) | ((x & 0xff00) >> 8);}
int str2regSize(char * str)
{
@@ -116,13 +118,13 @@ bool out_Modbus::getConfig()
aJsonObject * templateIdObj = aJson.getArrayItem(item->itemArg, 1);
if (templateIdObj->type != aJson_String || !templateIdObj->valuestring)
{
errorSerial<<F("Invalid template.")<<endl;
errorSerial<<F("MBUS: Invalid template.")<<endl;
return false;
}
aJsonObject * templateObj = aJson.getObjectItem(modbusObj, templateIdObj->valuestring);
if (! templateObj)
{
errorSerial<<F("Modbus template not found: ")<<templateIdObj->valuestring<<endl;
errorSerial<<F("MBUS: Modbus template not found: ")<<templateIdObj->valuestring<<endl;
return false;
}
@@ -173,12 +175,12 @@ if (!store)
store->timestamp=millisNZ();
if (getConfig())
{
infoSerial<<F("Modbus config loaded ")<< item->itemArr->name<<endl;
infoSerial<<F("MBUS: config loaded ")<< item->itemArr->name<<endl;
store->driverStatus = CST_INITIALIZED;
return 1;
}
else
{ errorSerial<<F("Modbus config error")<<endl;
{ errorSerial<<F("MBUS: config error")<<endl;
store->driverStatus = CST_FAILED;
return 0;
}
@@ -187,7 +189,7 @@ else
int out_Modbus::Stop()
{
debugSerial.println("Modbus De-Init");
debugSerial.println("MBUS: De-Init");
delete store;
item->setPersistent(NULL);
@@ -221,18 +223,24 @@ switch (regType) {
result = node.readInputRegisters(reg, count);
break;
default:
debugSerial<<F("Not supported reg type\n");
debugSerial<<F("MBUS: Not supported reg type\n");
}
mbusSlenceTimer = millisNZ();
if (result != node.ku8MBSuccess) errorSerial<<F("MBUS: Polling error ")<<_HEX(result)<<endl;
return (result == node.ku8MBSuccess);
}
int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uint8_t regType, uint16_t registerFrom, uint16_t registerTo, bool doExecution, bool * submitParam)
{
aJsonObject * paramObj = store->parameters->child;
bool is8bit = false;
bool tmpSubmitParam;
if (!submitParam) submitParam=&tmpSubmitParam;
*submitParam=true;
//bool is8bit = false;
while (paramObj)
{
aJsonObject *regObj=NULL;
@@ -246,11 +254,14 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
{
aJsonObject *typeObj = aJson.getObjectItem(paramObj, "type");
aJsonObject *mapObj = aJson.getObjectItem(paramObj, "map");
aJsonObject *idObj = aJson.getObjectItem(paramObj, "id");
aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
uint16_t data = node.getResponseBuffer(posInBuffer);
int8_t regType = PAR_I16;
uint32_t param =0;
itemCmd mappedParam;
bool executeWithoutCheck=false; //Afler recurrent check, all dublicatess and suppressing checked by recurrent
bool submitRecurrentOut = false; //false if recurrent check find duplicates
char buf[16];
//bool isSigned=false;
@@ -260,7 +271,7 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
case PAR_I16:
//isSigned=true;
param=data;
mappedParam.Int((int32_t)data);
mappedParam.Int((int32_t)(int16_t)data);
break;
case PAR_U16:
@@ -269,12 +280,12 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
break;
case PAR_I32:
//isSigned=true;
param = data | (node.getResponseBuffer(posInBuffer+1)<<16);
param = swap(data ) | swap(node.getResponseBuffer(posInBuffer+1)<<16);
mappedParam.Int((int32_t)param);
break;
case PAR_U32:
param = data | (node.getResponseBuffer(posInBuffer+1)<<16);
param = swap(data )| swap (node.getResponseBuffer(posInBuffer+1)<<16 );
mappedParam.Int((uint32_t)param);
break;
@@ -292,64 +303,112 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
case PAR_TENS:
param=data;
mappedParam.Tens((int32_t) data);
mappedParam.Tens((int16_t) data);
break;
case PAR_100:
param=data;
mappedParam.Tens_raw(data * (TENS_BASE/100));
mappedParam.Float((int32_t) data/100.);
mappedParam.Tens_raw((int16_t) data * (TENS_BASE/100));
mappedParam.Float((int32_t) (int16_t) data/100.);
}
debugSerial << F("MB got ")<<mappedParam.toString(buf,sizeof(buf))<< F(" from ")<<regType<<F(":")<<paramObj->name<<endl;
debugSerial << F("MBUSD: got ")<<mappedParam.toString(buf,sizeof(buf))<< F(" from ")<<regType<<F(":")<<paramObj->name<<endl;
if (mapObj && (mapObj->type==aJson_Array || mapObj->type==aJson_Object))
{
mappedParam=mappedParam.doReverseMapping(mapObj);
debugSerial << F("Mapped:")<<mappedParam.toString(buf,sizeof(buf))<<endl;
}
if (!mappedParam.isCommand() && !mappedParam.isValue()) //Not mapped
{
aJsonObject *nextRegObj = NULL;
int registerType = 0;
nextRegObj = aJson.getObjectItem(paramObj, "nextreg");
if (nextRegObj) registerType=MODBUS_HOLDING_REG_TYPE;
else
{
nextRegObj = aJson.getObjectItem(paramObj, "nextir");
if (nextRegObj) registerType=MODBUS_INPUT_REG_TYPE;
}
if (registerType && (nextRegObj->type) ==aJson_Int && (nextRegObj->valueint>= registerFrom) && (nextRegObj->valueint<=registerTo))
{
debugSerial<<F("Recurrent searching nextreg")<<endl;
mappedParam = findRegister(nextRegObj->valueint,nextRegObj->valueint-registerFrom,registerType,registerFrom,registerTo,false,&submitRecurrentOut);
executeWithoutCheck=true;
}
else errorSerial<<F("nextreg out of range")<<endl;
}
else
debugSerial << F("MBUSD: Mapped:")<<mappedParam.toString(buf,sizeof(buf))<<endl;
} //mapping
if (doExecution && idObj && idObj->type==aJson_Int)
switch (idObj->valueint)
{
case S_CMD:
mappedParam.saveItem(item,FLAG_COMMAND);
break;
case S_SET:
mappedParam.saveItem(item,FLAG_PARAMETERS);
}
if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{
aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,paramObj->name);
if (execObj)
{
bool submitParam=true;
aJsonObject * markObj = execObj;
if (execObj->type == aJson_Array) markObj = execObj->child;
//Retrive previous data
aJsonObject *lastMeasured = aJson.getObjectItem(execObj,"@S");
aJsonObject *lastMeasured = aJson.getObjectItem(markObj,"@S");
if (lastMeasured)
{
if (lastMeasured->type == aJson_Int)
{
if (lastMeasured->valueint == param)
submitParam=false; //supress repeating execution for same val
*submitParam=false; //supress repeating execution for same val
else lastMeasured->valueint=param;
}
}
else //No container to store value yet
{
debugSerial<<F("Add @S: ")<<paramObj->name<<endl;
aJson.addNumberToObject(execObj, "@S", (long) param);
}
if (submitParam)
{
//#ifdef MB_SUPPRESS_OUT_EQ_IN
debugSerial<<F("MBUS: Add @S: ")<<paramObj->name<<endl;
aJson.addNumberToObject(markObj, "@S", (long) param);
}
if (executeWithoutCheck)
{
if (doExecution && (submitRecurrentOut || *submitParam)) executeCommand(execObj, -1, mappedParam);
return mappedParam;
}
if (*submitParam)
{
// Compare with last submitted val (if @V NOT marked as NULL in config)
aJsonObject *settedValue = aJson.getObjectItem(execObj,"@V");
aJsonObject *settedValue = aJson.getObjectItem(markObj,"@V");
if (settedValue && settedValue->type==aJson_Int && (settedValue->valueint == param))
{
debugSerial<<F("Ignored - equal with setted val")<<endl;
debugSerial<<F("MBUSD: Ignored - equal with setted val")<<endl;
*submitParam=false;
}
else executeCommand(execObj, -1, mappedParam);
//#endif
else
{
if (doExecution) executeCommand(execObj, -1, mappedParam);
// if param updated by device and no new value queued to send - update @V to avoid "Ignored - equal with setted val"
if (settedValue && !(execObj->subtype & MB_NEED_SEND))
settedValue->valueint=param;
}
}
}
}
if (!is8bit) return 1;
return mappedParam;
}
paramObj=paramObj->next;
}
return is8bit;
return itemCmd();
}
@@ -368,7 +427,7 @@ return is8bit;
//if (readModbus(registerNum,MODBUS_HOLDING_REG_TYPE,1))
if (readModbus(registerNum,regType,1))
{
findRegister(registerNum,0,regType);
findRegister(registerNum,0,regType,registerNum,registerNum);
// data = node.getResponseBuffer(j);
}
}
@@ -384,7 +443,7 @@ return is8bit;
{ debugSerial<<endl;
for(int i=registerFrom;i<=registerTo;i++)
{
findRegister(i,i-registerFrom,regType);
findRegister(i,i-registerFrom,regType,registerFrom,registerTo);
}
//data = node.getResponseBuffer(j);
}
@@ -410,17 +469,20 @@ void out_Modbus::initLine()
#else
modbusSerial.begin(store->baud, (store->serialParam));
#endif
debugSerial<< store->baud << F("---")<< store->serialParam<<endl;
//debugSerial<< store->baud << F("---")<< store->serialParam<<endl;
node.begin(item->getArg(0), modbusSerial);
}
int out_Modbus::sendModbus(char * paramName, int32_t value, uint8_t regType)
{
if (!store) return -1;
if (!store) {errorSerial<<F(" internal send error - no store")<<endl; return -1;}
aJsonObject * templateParamObj = aJson.getObjectItem(store->parameters, paramName);
if (!templateParamObj) return -1;
if (!templateParamObj) {errorSerial<<F(" internal send error - no template")<<endl; return -1;}
aJsonObject * regObj = aJson.getObjectItem(templateParamObj, "reg");
if (!regObj) return -2;
if (!regObj) {errorSerial<<F(" internal send error - no regObj")<<endl; return -2;}
int res = -1;
// int8_t regType = PAR_I16;
@@ -438,8 +500,8 @@ int out_Modbus::sendModbus(char * paramName, int32_t value, uint8_t regType)
break;
case PAR_I32:
case PAR_U32:
res = node.writeSingleRegister(regObj->valueint,value & 0xFFFF);
res += node.writeSingleRegister(regObj->valueint+1,value >> 16) ;
res = node.writeSingleRegister(regObj->valueint,swap(value & 0xFFFF));
res += node.writeSingleRegister(regObj->valueint+1,swap(value >> 16)) ;
break;
case PAR_U8L:
@@ -452,7 +514,8 @@ int out_Modbus::sendModbus(char * paramName, int32_t value, uint8_t regType)
res = node.writeSingleRegister(regObj->valueint,(value & 0xFFFF)>> 8);
break;
}
debugSerial<<F("MB_SEND Res: ")<<res<<F(" ")<<paramName<<" reg:"<<regObj->valueint<<F(" val:")<<value<<F(" ival:")<<(int32_t) value<<endl;
mbusSlenceTimer = millisNZ();
debugSerial<<F("Res: ")<<res<<F(" ")<<paramName<<" reg:"<<regObj->valueint<<F(" val:")<<value<<endl;
return ( res == 0);
}
@@ -461,17 +524,22 @@ int out_Modbus::Poll(short cause)
if (cause==POLLING_SLOW) return 0;
bool lineInitialized = false;
if (modbusBusy || (Status() != CST_INITIALIZED)) return 0;
if (modbusBusy || (Status() != CST_INITIALIZED) || ( mbusSlenceTimer && !isTimeOver(mbusSlenceTimer,millis(),100))) return 0;
aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{
aJsonObject *execObj = itemParametersObj->child;
while (execObj && execObj->type == aJson_Object)
while (execObj && (execObj->type == aJson_Object) || (execObj->type == aJson_Array) )
{
if ((execObj->subtype & MB_NEED_SEND) && !(execObj->subtype & MB_SEND_ERROR))
{
aJsonObject *outValue = aJson.getObjectItem(execObj,"@V");
aJsonObject * markObj = execObj;
if (execObj->type == aJson_Array) markObj = execObj->child;
aJsonObject *outValue = aJson.getObjectItem(markObj,"@V");
if (outValue)
{
modbusBusy=1;
@@ -480,18 +548,22 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
lineInitialized=true;
initLine();
}
debugSerial<<"MBUS: SEND "<<item->itemArr->name<<" ";
switch (sendModbus(execObj->name,outValue->valueint,outValue->subtype))
{
case 1: //success
execObj->subtype&=~ MB_NEED_SEND;
///return 1; //relax
break;
case 0: //fault
execObj->subtype |= MB_SEND_ERROR;
errorSerial<<F("MBus ")<<execObj->name<<F(" send error")<<endl;
errorSerial<<F("MBUS: ")<<execObj->name<<F(" send error. ");
if ((execObj->subtype & 3) != MB_SEND_ATTEMPTS) execObj->subtype++;
errorSerial<<"Attempt: "<< (execObj->subtype & 3) <<endl;
break;
default: //param not found
errorSerial<<F("MBus param ")<<execObj->name<<F(" not found")<<endl;
errorSerial<<F("MBUS: param ")<<execObj->name<<F(" not found")<<endl;
execObj->subtype&=~ MB_NEED_SEND;
}
}
@@ -502,17 +574,24 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
}
if (isTimeOver(store->timestamp,millis(),store->pollingInterval))
if (isTimeOver(store->timestamp,millis(),store->pollingInterval) && ( !mbusSlenceTimer || isTimeOver(mbusSlenceTimer,millis(),100)))
{
// Clean_up SEND_ERROR flag
// Clean_up FLAG_SEND_ERROR flag
if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{
aJsonObject *execObj = itemParametersObj->child;
while (execObj && execObj->type == aJson_Object)
while (execObj && (execObj->type == aJson_Object) || (execObj->type == aJson_Array))
{
if (execObj->subtype & MB_SEND_ERROR) execObj->subtype&=~ MB_SEND_ERROR;
if ((execObj->subtype & 0x3) >= MB_SEND_ATTEMPTS) execObj->subtype&=~ MB_NEED_SEND;
if ((execObj->subtype & 0x3) >= MB_SEND_ATTEMPTS)
{
//execObj->subtype&=~ MB_NEED_SEND;
//Clean ERROR, NEED, Attempts
errorSerial<<"MBUS: send failed "<<item->itemArr->name<<endl;
execObj->subtype = 0;
}
execObj=execObj->next;
}
}
@@ -520,7 +599,7 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
// if some polling configured
if (store->pollingRegisters || store->pollingIrs)
{
debugSerial<<F("Poll ")<< item->itemArr->name << endl;
debugSerial<<F("MBUSD: Poll ")<< item->itemArr->name << endl;
modbusBusy=1;
if (!lineInitialized)
@@ -531,7 +610,7 @@ if (store->pollingRegisters || store->pollingIrs)
pollModbus(store->pollingRegisters,MODBUS_HOLDING_REG_TYPE);
pollModbus(store->pollingIrs,MODBUS_INPUT_REG_TYPE);
debugSerial<<F("endPoll ")<< item->itemArr->name << endl;
debugSerial<<F("MBUSD: endPoll ")<< item->itemArr->name << endl;
//Non blocking waiting to release line
uint32_t time = millis();
@@ -561,7 +640,8 @@ if (!suffixCode) return 0;
char *suffixStr =templateParamObj->name;
// We have find template for suffix or suffixCode
long Value = 0;
itemCmd cmdValue = itemCmd(ST_VOID,CMD_VOID);
long Value = 0;
int8_t regType = PAR_I16;
aJsonObject * typeObj = aJson.getObjectItem(templateParamObj, "type");
aJsonObject * mapObj = aJson.getObjectItem(templateParamObj, "map");
@@ -577,47 +657,60 @@ aJsonObject * mapObj = aJson.getObjectItem(templateParamObj, "map");
case PAR_I8H:
case PAR_I8L:
Value=cmd.doMapping(mapObj).getInt();
cmdValue=cmd.doMapping(mapObj);
if (!cmdValue.isValue())return 0;
Value=cmdValue.getInt();
break;
case PAR_TENS:
Value=cmd.doMapping(mapObj).getTens();
cmdValue=cmd.doMapping(mapObj);
if (!cmdValue.isValue())return 0;
Value=cmdValue.getTens();
break;
case PAR_100:
Value=cmd.doMapping(mapObj).getTens_raw()*(100/TENS_BASE);
cmdValue=cmd.doMapping(mapObj);
if (!cmdValue.isValue())return 0;
Value=cmdValue.getTens_raw()*(100/TENS_BASE);
}
debugSerial<<F("MB suffix:")<<suffixStr<< F(" Val: ")<<Value<<endl;
debugSerial<<F("MBUSD: suffix:")<<suffixStr<< F(" Val: ")<<Value<<endl;
aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{
aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,suffixStr);
if (execObj && execObj->type == aJson_Object)
if (execObj && (execObj->type == aJson_Object) || (execObj->type == aJson_Array))
{
/*
aJsonObject *polledValue = aJson.getObjectItem(execObj,"@S");
if (polledValue && polledValue->type == aJson_Int && (polledValue->valueint == Value))
{
debugSerial<<F("Ignored - not changed")<<endl;
}
else
else */
{ //Schedule update
execObj->subtype |= MB_NEED_SEND;
aJsonObject *outValue = aJson.getObjectItem(execObj,"@V");
aJsonObject * markObj = execObj;
if (execObj->type == aJson_Array) markObj = execObj->child;
aJsonObject *outValue = aJson.getObjectItem(markObj,"@V");
if (outValue) // Existant. Preserve original @type
{
outValue->valueint=Value;
outValue->subtype =regType & 0xF;
if (outValue->type == aJson_Int) polledValue->valueint=Value; //to pevent suppressing to change back to previously polled value if this occurs before next polling
}
else //No container to store value yet
// If no @V in config - creating with INT type - normal behavior - no supress in-to-out
{
debugSerial<<F("Add @V: ")<<execObj->name<<endl;
aJson.addNumberToObject(execObj, "@V", Value);
outValue = aJson.getObjectItem(execObj,"@V");
aJson.addNumberToObject(markObj, "@V", Value);
outValue = aJson.getObjectItem(markObj,"@V");
if (outValue) outValue->subtype =regType & 0xF;
}
aJsonObject *polledValue = aJson.getObjectItem(markObj,"@S");
if (polledValue && outValue->type == aJson_Int) polledValue->valueint=Value; //to pevent suppressing to change back to previously polled value if this occurs before next polling
}
}
}
@@ -663,7 +756,7 @@ else
}
templateParamObj=templateParamObj->next;
}
if (!suffixFinded) errorSerial<<F("No template for ")<<subItem<<F(" or suffix ")<<suffixCode<<endl;
if (!suffixFinded) errorSerial<<F("MBUS: No template for ")<<subItem<<F(" or suffix ")<<suffixCode<<endl;
}
return res;
}

View File

@@ -43,7 +43,7 @@ public:
protected:
mbPersistent * store;
bool getConfig();
int findRegister(int registerNum, int posInBuffer, int regType);
itemCmd findRegister(uint16_t registerNum, uint16_t posInBuffer, uint8_t regType, uint16_t registerFrom, uint16_t registerTo, bool doExecution = true, bool * submitParam = NULL);
void pollModbus(aJsonObject * reg, int regType);
void initLine();
int sendModbus(char * paramName, int32_t value, uint8_t regType);

View File

@@ -50,7 +50,7 @@ int out_Motor::Setup()
{
abstractOut::Setup();
getConfig();
debugSerial.println("Motor Init");
debugSerial.println("Motor: Init");
pinMode(pinUp,OUTPUT);
pinMode(pinDown,OUTPUT);
@@ -61,8 +61,8 @@ digitalWrite(pinDown,INACTIVE);
pinMode(pinFeedback, INPUT);
item->setExt(0);
item->clearFlag(ACTION_NEEDED);
item->clearFlag(ACTION_IN_PROCESS);
item->clearFlag(FLAG_ACTION_NEEDED);
item->clearFlag(FLAG_ACTION_IN_PROCESS);
driverStatus = CST_INITIALIZED;
motorQuote = MOTOR_QUOTE;
return 1;
@@ -70,7 +70,7 @@ return 1;
int out_Motor::Stop()
{
debugSerial.println("Motor De-Init");
debugSerial.println("Motor: De-Init");
digitalWrite(pinUp,INACTIVE);
digitalWrite(pinDown,INACTIVE);
@@ -105,13 +105,13 @@ if (cause==POLLING_SLOW) return 0;
int curPos = -1;
int targetPos = -1;
int dif;
if (!item->getFlag(ACTION_NEEDED)) return 0;
if (!item->getFlag(FLAG_ACTION_NEEDED)) return 0;
if (!item->getFlag(ACTION_IN_PROCESS))
if (!item->getFlag(FLAG_ACTION_IN_PROCESS))
{
if (motorQuote)
{
item->setFlag(ACTION_IN_PROCESS);
item->setFlag(FLAG_ACTION_IN_PROCESS);
motorQuote--;
}
else return 0;
@@ -145,13 +145,13 @@ if (curPos>255) curPos=255;
}
if (motorOfftime && isTimeOver(motorOfftime,millis(),maxOnTime))
{dif = 0; debugSerial<<F("Motor timeout")<<endl;}
{dif = 0; debugSerial<<F("Motor: timeout")<<endl;}
else if (curPos>=0)
dif=targetPos-curPos;
else
dif=targetPos-255/2; // Have No feedback
debugSerial<<F("In:")<<pinFeedback<<F(" Val:")<<fb<<F("/")<<curPos<<F("->")<<targetPos<<F(" delta:")<<dif<<endl;
debugSerial<<F("Motor: in:")<<pinFeedback<<F(" Val:")<<fb<<F("/")<<curPos<<F("->")<<targetPos<<F(" delta:")<<dif<<endl;
if (dif<-POS_ERR)
{
@@ -241,12 +241,12 @@ else
}
else //Target zone
{ debugSerial.println("Target");
{ debugSerial.println("Motor: Target");
digitalWrite(pinUp,INACTIVE);
digitalWrite(pinDown,INACTIVE);
item->setExt(0);
item->clearFlag(ACTION_NEEDED);
item->clearFlag(ACTION_IN_PROCESS);
item->clearFlag(FLAG_ACTION_NEEDED);
item->clearFlag(FLAG_ACTION_IN_PROCESS);
motorQuote++;
}
@@ -263,43 +263,25 @@ int out_Motor::getChanType()
int out_Motor::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
{
//int chActive = item->isActive();
//bool toExecute = (chActive>0);
int suffixCode = cmd.getSuffix();
//itemCmd st(ST_PERCENTS,CMD_VOID);
if (cmd.isCommand() && !suffixCode) suffixCode=S_CMD; //if some known command find, but w/o correct suffix - got it
item->setFlag(ACTION_NEEDED);
item->setFlag(FLAG_ACTION_NEEDED);
switch(suffixCode)
{
case S_NOTFOUND:
// turn on and set
toExecute = true;
debugSerial<<F("Forced execution");
debugSerial<<F("Motor: Forced execution");
case S_SET:
//case S_ESET:
if (!cmd.isValue()) return 0;
// item->setVal(cmd.getPercents());
if (item->getExt()) item->setExt(millisNZ()); //Extend motor time
/*
st.assignFrom(cmd);
//Store
st.saveItem(item);
if (!suffixCode)
{
if (chActive>0 && !st.getPercents()) item->setCmd(CMD_OFF);
if (chActive==0 && st.getPercents()) item->setCmd(CMD_ON);
item->SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED);
if (item->getExt()) item->setExt(millisNZ()); //Extend motor time
}
else item->SendStatus(SEND_PARAMETERS | SEND_DEFFERED);
*/
return 1;
//break;
case S_CMD:
//item->setCmd(cmd.getCmd());
switch (cmd.getCmd())
{
case CMD_ON:
@@ -307,7 +289,6 @@ case S_CMD:
return 1;
case CMD_OFF:
////item->SendStatus(SEND_COMMAND);
if (item->getExt()) item->setExt(millisNZ()); //Extend motor time
return 1;

View File

@@ -97,6 +97,7 @@ int out_Multivent::getChanType()
int out_Multivent::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
{
if (cmd.getCmd()==CMD_DISABLE || cmd.getCmd()==CMD_ENABLE) return 0;
int suffixCode = cmd.getSuffix();
if (cmd.isCommand() && !suffixCode) suffixCode=S_CMD; //if some known command find, but w/o correct suffix - got it
@@ -155,14 +156,14 @@ while (i)
case CMD_OFF:
cmd.Percents255(0);
}
if (cmdObj->valueint == CMD_ON && setObj->valueint<20)
if (isNotRetainingStatus() && (cmdObj->valueint == CMD_ON) && (setObj->valueint<20))
{
setObj->valueint=30;
cmd.Percents255(30);
//if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,SEND_PARAMETERS,i->name);
//if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_PARAMETERS,i->name);
}
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,SEND_COMMAND|SEND_PARAMETERS,i->name);
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_COMMAND|FLAG_PARAMETERS,i->name);
}
else if (setObj && cmdObj && suffixCode == S_FAN && cmd.isValue())
@@ -175,7 +176,7 @@ while (i)
debugSerial<<"Turning ON"<<endl;
cmdObj->valueint = CMD_ON;
cmd.Cmd(CMD_ON);
//if (isNotRetainingStatus()) item->SendStatusImmediate(itemCmd().Cmd(CMD_ON),SEND_COMMAND,i->name);
//if (isNotRetainingStatus()) item->SendStatusImmediate(itemCmd().Cmd(CMD_ON),FLAG_COMMAND,i->name);
}
setObj->valueint = cmd.getInt();
@@ -186,20 +187,20 @@ while (i)
{ debugSerial<<"Turning OFF"<<endl;
cmdObj->valueint = CMD_OFF;
cmd.Cmd(CMD_OFF);
//if (isNotRetainingStatus()) item->SendStatusImmediate(itemCmd().Cmd(CMD_OFF),SEND_COMMAND,i->name);
//if (isNotRetainingStatus()) item->SendStatusImmediate(itemCmd().Cmd(CMD_OFF),FLAG_COMMAND,i->name);
}
setObj->valueint = 0;
}
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,SEND_PARAMETERS|SEND_COMMAND,i->name);
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_PARAMETERS|FLAG_COMMAND,i->name);
}
else if (setObj && cmd.isValue())
{
setObj->valueint = cmd.getPercents255();
//publishTopic(i->name,setObj->valueint,"/set");
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,SEND_PARAMETERS,i->name);
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_PARAMETERS,i->name);
}
if (cascadeObj) executeCommand(cascadeObj,-1,cmd);
}
@@ -229,6 +230,9 @@ debugSerial << F("Total V:")<<totalV<<F(" active V:")<<activeV/255<< F(" fan%:")
executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV).Cmd((fanV)?CMD_ON:CMD_OFF));
//Move gates only if fan is actually on
if (!fanV) return 1;
i=NULL;
if (gatesObj) i = gatesObj->child; //Pass 2: re-distribute airflow
@@ -250,11 +254,11 @@ while (i)
debugSerial<<i->name<<(" Req:")<<requestedV/255<<F(" Out:")<<out<<endl;
}
// executeCommand(i,-1,itemCmd().Percents255(out));
if (out != outObj->valueint)
if ((out != outObj->valueint))
{
//report out
executeCommand(i,-1,itemCmd().Percents255(out));
executeCommand(i,-1,itemCmd().Percents255(out));
outObj->valueint=out;
}
}
@@ -262,37 +266,6 @@ while (i)
}
return 1;
switch(suffixCode)
{
case S_NOTFOUND:
// turn on and set
toExecute = true;
debugSerial<<F("Forced execution");
case S_SET:
if (!cmd.isValue()) return 0;
return 1;
//break;
case S_CMD:
//item->setCmd(cmd.getCmd());
switch (cmd.getCmd())
{
case CMD_ON:
return 1;
case CMD_OFF:
return 1;
} //switch cmd
break;
} //switch suffix
debugSerial<<F("Unknown cmd")<<endl;
return 0;
}
#endif

View File

@@ -14,6 +14,7 @@ bool out_pid::getConfig()
double kI=0.0;
double kD=0.0;
int direction = DIRECT;
bool limits = false;
// Retrieve and store
if (!store || !item || !item->itemArg || (item->itemArg->type != aJson_Array) || aJson.getArraySize(item->itemArg)<1)
@@ -25,11 +26,11 @@ bool out_pid::getConfig()
aJsonObject * kPIDObj = aJson.getArrayItem(item->itemArg, 0);
if (!kPIDObj || kPIDObj->type != aJson_Array)
{
errorSerial<<F("Invalid PID param array.")<<endl;
errorSerial<<F("PID: Invalid param array.")<<endl;
return false;
}
double outMin=0.; //UNUSED
double outMax=255.;//UNUSED
double outMin=0.;
double outMax=255.;
float dT=5.;
uint32_t alarmTO=PERIOD_THERMOSTAT_FAILED;
@@ -37,13 +38,13 @@ bool out_pid::getConfig()
switch (aJson.getArraySize(kPIDObj))
{ case 8: //kP,kI,kD,dT, alarmTO, alarmVal, outMin, outMax
param = aJson.getArrayItem(kPIDObj, 7);
if (param->type == aJson_Float) outMax=param->valuefloat;
else if (param->type == aJson_Int) outMax=param->valueint;
if (param->type == aJson_Float) {outMax=param->valuefloat;limits=true;}
else if (param->type == aJson_Int) {outMax=param->valueint;limits=true;}
case 7: //kP,kI,kD,dT alarmTO, alarmVal, outMin
param = aJson.getArrayItem(kPIDObj, 6);
if (param->type == aJson_Float) outMin=param->valuefloat;
else if (param->type == aJson_Int) outMin=param->valueint;
if (param->type == aJson_Float) {outMin=param->valuefloat;limits=true;}
else if (param->type == aJson_Int) {outMin=param->valueint;limits=true;}
case 6: //kP,kI,kD,dT, alarmTO, alarmVal
case 5: //kP,kI,kD,dT, alarmTO
@@ -99,10 +100,10 @@ bool out_pid::getConfig()
{store->pid= new PID (&store->input, &store->output, &store->setpoint, kP, kI, kD, direction);
if (!store->pid) return false;
store->pid->SetMode(AUTOMATIC);
//store->pid->SetOutputLimits(outMin,outMax);
if (limits) store->pid->SetOutputLimits(outMin,outMax);
store->pid->SetSampleTime(dT*1000.0);
return true;}
else errorSerial<<F("PID already initialized")<<endl;
else errorSerial<<F("PID: already initialized")<<endl;
return false;
}
@@ -119,16 +120,16 @@ store->pid=NULL;
//store->timestamp=millis();
if (getConfig())
{
infoSerial<<F("PID config loaded ")<< item->itemArr->name<<endl;
infoSerial<<F("PID: config loaded ")<< item->itemArr->name<<endl;
//item->On(); // Turn ON pid by default
// if (item->getCmd()) item->setFlag(SEND_COMMAND);
// if (item->itemVal) item->setFlag(SEND_PARAMETERS);
// if (item->getCmd()) item->setFlag(FLAG_COMMAND);
// if (item->itemVal) item->setFlag(FLAG_PARAMETERS);
store->prevOut = -2.0;
store->driverStatus = CST_INITIALIZED;
return 1;
}
else
{ errorSerial<<F("PID config error")<<endl;
{ errorSerial<<F("PID: config error")<<endl;
store->driverStatus = CST_FAILED;
return 0;
}
@@ -137,7 +138,7 @@ else
int out_pid::Stop()
{
debugSerial.println("PID De-Init");
debugSerial.println("PID: De-Init");
if (store) delete (store->pid);
delete store;
item->setPersistent(NULL);
@@ -162,25 +163,33 @@ int out_pid::Poll(short cause)
{
if (cause==POLLING_SLOW) return 0;
if (store && store->pid && (Status() == CST_INITIALIZED) && item && (item->getCmd()!=CMD_OFF))
{
//double prevOut=store->output;
//itemCmd st;
//st.loadItem(item);
//short cmd = st.getCmd();
if (item->getCmd() != CMD_OFF && item->getCmd() != CMD_DISABLE)
{
if (item->getCmd() != CMD_OFF && ! item->getFlag(FLAG_DISABLED))
{
if(store->pid->Compute() )
{
int alarmVal;
if (store->alarmArmed && (alarmVal=getAlarmVal()>=0)) store->output=alarmVal;
debugSerial<<F("PID ")<<item->itemArr->name<<F(" set:")<<store->setpoint<<F(" in:")<<store->input<<(" out:") << store->output <<F(" P:")<<store->pid->GetKp() <<F(" I:")<<store->pid->GetKi() <<F(" D:")<<store->pid->GetKd();
if (store->alarmArmed) debugSerial << F(" Alarm");
float alarmVal;
if (store->alarmArmed && ((alarmVal=getAlarmVal())>=0.)) store->output=alarmVal;
debugSerial<<F("PID: ")<<item->itemArr->name<<F(" set:")<<store->setpoint<<F(" in:")<<store->input<<(" out:") << store->output <<F(" P:")<<store->pid->GetKp() <<F(" I:")<<store->pid->GetKi() <<F(" D:")<<store->pid->GetKd();
//if (item->getFlag(FLAG_DISABLED)) debugSerial << F(" <DIS>");
if (store->alarmArmed) debugSerial << F(" <ALM>");
debugSerial<<endl;
if ((abs(store->output-store->prevOut)>OUTPUT_TRESHOLD) && !store->alarmArmed)
if (((abs(store->output-store->prevOut)>OUTPUT_TRESHOLD) || (item->getFlag(FLAG_ACTION_NEEDED))) && !store->alarmArmed)
{
aJsonObject * oCmd = aJson.getArrayItem(item->itemArg, 1);
itemCmd value((float) (store->output));// * (100./255.)));
if (((store->prevOut == 0.) && (store->output>0)) || item->getFlag(FLAG_ACTION_NEEDED))
// if ((item->getFlag(FLAG_ACTION_NEEDED)) && (store->output>0.))
{
executeCommand(oCmd,-1,itemCmd().Cmd(CMD_ON));
// item->clearFlag(FLAG_ACTION_NEEDED);
}
item->clearFlag(FLAG_ACTION_NEEDED);
itemCmd value((float) (store->output));
value.setSuffix(S_SET);
executeCommand(oCmd,-1,value);
store->prevOut=store->output;
@@ -192,37 +201,39 @@ if (store && store->pid && (Status() == CST_INITIALIZED) && item && (item->getCm
alarm(true);
}
}
}
}
return 1;//store->pollingInterval;
};
int out_pid::getAlarmVal()
float out_pid::getAlarmVal()
{
aJsonObject * kPIDObj = aJson.getArrayItem(item->itemArg, 0);
if (!kPIDObj || kPIDObj->type != aJson_Array)
{
errorSerial<<F("Invalid PID param array.")<<endl;
return -1;
errorSerial<<F("PID: Invalid param array.")<<endl;
return -1.;
}
int outAlarm=0;
float outAlarm=0.;
double kP=0.;
bool alarmValDefined = false;
aJsonObject * param;
switch (aJson.getArraySize(kPIDObj))
{
case 7: //kP,kI,kD, alarmTO, alarmVal, outMin, outMax
case 6: //kP,kI,kD, alarmTO, alarmVal, outMin
case 5: //kP,kI,kD, alarmTO, alarmVal
param = aJson.getArrayItem(kPIDObj, 4);
case 8: //kP,kI,kD,dT, alarmTO, alarmVal, outMin, outMax
case 7: //kP,kI,kD,dT, alarmTO, alarmVal, outMin
case 6: //kP,kI,kD,dT,alarmTO, alarmVal
param = aJson.getArrayItem(kPIDObj, 5);
alarmValDefined=true;
if (param->type == aJson_Float) outAlarm=param->valuefloat;
else if (param->type == aJson_Int) outAlarm=param->valueint;
else alarmValDefined=false;
case 4: //kP,kI,kD, alarmTO
case 5: //kP,kI,kD,dT, alarmTO
case 4: //kP,kI,kD,dT
case 3: //kP,kI,kD
case 2: //kP,kI
case 1: //kP
@@ -230,13 +241,14 @@ int out_pid::getAlarmVal()
if (param->type == aJson_Float) kP=param->valuefloat;
else if (param->type == aJson_Int) kP=param->valueint;
{
if (kP<0)
if (kP<0.)
{
if (!alarmValDefined) outAlarm = 0.;
}
else if (!alarmValDefined) outAlarm = .255;
else if (!alarmValDefined) outAlarm = 255.;
}
}
// debugSerial<<F("Alarm value: ")<<outAlarm<< " ";
return outAlarm;
}
@@ -248,7 +260,7 @@ if (!item || !item->itemArg) return;
{
float outAlarm=getAlarmVal();
errorSerial<<item->itemArr->name<<F(" PID alarm. ")<<endl;
if (outAlarm>=0)
if (outAlarm>=0.)
{
errorSerial<<F("Set out to ")<<outAlarm<<endl;
aJsonObject * oCmd = aJson.getArrayItem(item->itemArg, 1);
@@ -287,7 +299,7 @@ case S_VAL:
// Input value for PID
if (!cmd.isValue()) return 0;
store->input=cmd.getFloat();
debugSerial<<F("Input value:")<<store->input<<endl;
debugSerial<<F("PID: ")<< item->itemArr->name <<F(" Input value:")<<store->input<<endl;
store->alarmTimer=millis();
if (store->alarmArmed)
@@ -301,11 +313,11 @@ return 1;
case S_NOTFOUND:
case S_SET:
//case S_ESET:
// Setpoint for PID
if (!cmd.isValue()) return 0;
store->setpoint=cmd.getFloat();
debugSerial<<F("Setpoint:")<<store->setpoint<<endl;
debugSerial<<F("PID: ")<< item->itemArr->name <<F(" Setpoint:")<<store->setpoint<<endl;
{
aJsonObject * itemCascadeObj = aJson.getArrayItem(item->itemArg, 2);
@@ -313,11 +325,12 @@ if (itemCascadeObj) executeCommand(itemCascadeObj,-1,cmd);
}
//cmd.saveItem(item);
//item->SendStatus(SEND_PARAMETERS);
//item->SendStatus(FLAG_PARAMETERS);
return 1;
//break;
case S_CMD:
case S_CTRL:
{
aJsonObject * oCmd = aJson.getArrayItem(item->itemArg, 1);
short command = cmd.getCmd();
@@ -335,16 +348,23 @@ case S_CMD:
case CMD_FAN:
case CMD_DRY:
executeCommand(oCmd,-1,value);
executeCommand(oCmd,-1,value);
executeCommand(oCmd,-1,itemCmd().Cmd((item->getFlag(FLAG_DISABLED))?CMD_DISABLE:CMD_ENABLE));
item->SendStatus(FLAG_FLAGS);
return 1;
case CMD_ENABLE:
item->setCmd(CMD_ENABLE);
item->SendStatus(SEND_COMMAND);
//item->setCmd(CMD_ENABLE);
//item->SendStatus(FLAG_COMMAND);
item->setFlag(FLAG_ACTION_NEEDED);
executeCommand(oCmd,-1,value);
store->prevOut=-2.0;
return 1;
case CMD_DISABLE:
item->setCmd(CMD_DISABLE);
item->SendStatus(SEND_COMMAND);
//item->setCmd(CMD_DISABLE);
//item->SendStatus(FLAG_COMMAND);
executeCommand(oCmd,-1,value);
return 1;
/*
case CMD_OFF:
@@ -357,11 +377,11 @@ case S_CMD:
} */
default:
debugSerial<<F("Unknown cmd ")<<cmd.getCmd()<<endl;
debugSerial<<F("PID: Unknown cmd ")<<cmd.getCmd()<<endl;
} //switch cmd
}
default:
debugSerial<<F("Unknown suffix ")<<suffixCode<<endl;
debugSerial<<F("PID: Unknown suffix ")<<suffixCode<<endl;
} //switch suffix
return 0;

View File

@@ -41,6 +41,6 @@ public:
protected:
pidPersistent * store;
bool getConfig();
int getAlarmVal();
float getAlarmVal();
};
#endif

View File

@@ -41,8 +41,8 @@ debugSerial<<F("Relay-Out #")<<pin<<F(" init")<<endl;
pinMode(pin, OUTPUT);
digitalWrite(pin,INACTIVE);
if (item) item->setExt(0);
//if (item->getCmd()) item->setFlag(SEND_COMMAND);
//if (item->itemVal) item->setFlag(SEND_PARAMETERS);
//if (item->getCmd()) item->setFlag(FLAG_COMMAND);
//if (item->itemVal) item->setFlag(FLAG_PARAMETERS);
driverStatus = CST_INITIALIZED;
if (item->isActive()>0) ///????
{

View File

@@ -209,9 +209,9 @@ case S_HSV:
{
if (chActive>0 && !st.getPercents()) item->setCmd(CMD_OFF);
if (chActive==0 && st.getPercents()) item->setCmd(CMD_ON);
item->SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED);
item->SendStatus(SEND_COMMAND | FLAG_PARAMETERS | FLAG_SEND_DEFFERED);
}
else item->SendStatus(SEND_PARAMETERS | SEND_DEFFERED);
else item->SendStatus(FLAG_PARAMETERS | FLAG_SEND_DEFFERED);
}
return 1;
//break;
@@ -234,7 +234,7 @@ case S_CMD:
if (st.getInt() ) //Stored smthng
{
item->SendStatus(SEND_COMMAND | SEND_PARAMETERS);
item->SendStatus(SEND_COMMAND | FLAG_PARAMETERS);
debugSerial<<F("Restored: ")<<st.param.h<<F(",")<<st.param.s<<F(",")<<st.param.v<<endl;
}
else
@@ -245,7 +245,7 @@ case S_CMD:
// Store
//item->setVal(st.getInt());
st.saveItem(item);
item->SendStatus(SEND_COMMAND | SEND_PARAMETERS );
item->SendStatus(SEND_COMMAND | FLAG_PARAMETERS );
}
PixelCtrl(st,from,to);

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