mirror of https://github.com/arendst/Tasmota.git
v3.9.4
This commit is contained in:
parent
cde3982940
commit
d392cf2f77
Binary file not shown.
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
// mkdir and chmod arduino folder to 777
|
||||||
|
//
|
||||||
|
//var_dump($_FILES);
|
||||||
|
|
||||||
|
$image = basename($_FILES["file"]["name"]);
|
||||||
|
$target_file = "arduino/".$image;
|
||||||
|
$hostname = $_SERVER['SERVER_NAME'];
|
||||||
|
|
||||||
|
if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) {
|
||||||
|
echo "The file $image has been uploaded to OTA server $hostname. \n";
|
||||||
|
} else {
|
||||||
|
echo "Sorry, there was an error uploading your file $image to OTA server $hostname. \n";
|
||||||
|
}
|
||||||
|
?>
|
|
@ -0,0 +1,112 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# espupload by Theo Arends - 20170103
|
||||||
|
#
|
||||||
|
# Uploads binary file to OTA server
|
||||||
|
#
|
||||||
|
# Execute: espupload -i <Host_IP_address> -p <Host_port> -f <sketch.bin>
|
||||||
|
#
|
||||||
|
# Needs pycurl
|
||||||
|
# - pip install pycurl
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import optparse
|
||||||
|
import logging
|
||||||
|
import pycurl
|
||||||
|
|
||||||
|
HOST_ADDR = "domus1"
|
||||||
|
HOST_PORT = 80
|
||||||
|
HOST_URL = "/api/upload-arduino.php"
|
||||||
|
|
||||||
|
def upload(hostAddr, hostPort, filename):
|
||||||
|
url = 'http://%s:%d%s' % (hostAddr, hostPort, HOST_URL)
|
||||||
|
c = pycurl.Curl()
|
||||||
|
c.setopt(c.URL, url)
|
||||||
|
# The "Expect:" is there to suppress "Expect: 100-continue" behaviour that is
|
||||||
|
# the default in libcurl when posting large bodies (and fails on lighttpd).
|
||||||
|
c.setopt(c.HTTPHEADER, ["Expect:"])
|
||||||
|
c.setopt(c.HTTPPOST, [('file', (c.FORM_FILE, filename, )), ])
|
||||||
|
c.perform()
|
||||||
|
c.close()
|
||||||
|
|
||||||
|
def parser():
|
||||||
|
parser = optparse.OptionParser(
|
||||||
|
usage = "%prog [options]",
|
||||||
|
description = "Upload image to over the air Host server for the esp8266 module with OTA support."
|
||||||
|
)
|
||||||
|
|
||||||
|
# destination ip and port
|
||||||
|
group = optparse.OptionGroup(parser, "Destination")
|
||||||
|
group.add_option("-i", "--host_ip",
|
||||||
|
dest = "host_ip",
|
||||||
|
action = "store",
|
||||||
|
help = "Host IP Address.",
|
||||||
|
default = HOST_ADDR
|
||||||
|
)
|
||||||
|
group.add_option("-p", "--host_port",
|
||||||
|
dest = "host_port",
|
||||||
|
type = "int",
|
||||||
|
help = "Host server ota Port. Default 80",
|
||||||
|
default = HOST_PORT
|
||||||
|
)
|
||||||
|
parser.add_option_group(group)
|
||||||
|
|
||||||
|
# image
|
||||||
|
group = optparse.OptionGroup(parser, "Image")
|
||||||
|
group.add_option("-f", "--file",
|
||||||
|
dest = "image",
|
||||||
|
help = "Image file.",
|
||||||
|
metavar="FILE",
|
||||||
|
default = None
|
||||||
|
)
|
||||||
|
parser.add_option_group(group)
|
||||||
|
|
||||||
|
# output group
|
||||||
|
group = optparse.OptionGroup(parser, "Output")
|
||||||
|
group.add_option("-d", "--debug",
|
||||||
|
dest = "debug",
|
||||||
|
help = "Show debug output. And override loglevel with debug.",
|
||||||
|
action = "store_true",
|
||||||
|
default = False
|
||||||
|
)
|
||||||
|
parser.add_option_group(group)
|
||||||
|
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
return options
|
||||||
|
# end parser
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
# get options
|
||||||
|
options = parser()
|
||||||
|
|
||||||
|
# adapt log level
|
||||||
|
loglevel = logging.WARNING
|
||||||
|
if (options.debug):
|
||||||
|
loglevel = logging.DEBUG
|
||||||
|
# end if
|
||||||
|
|
||||||
|
# logging
|
||||||
|
logging.basicConfig(level = loglevel, format = '%(asctime)-8s [%(levelname)s]: %(message)s', datefmt = '%H:%M:%S')
|
||||||
|
|
||||||
|
logging.debug("Options: %s", str(options))
|
||||||
|
|
||||||
|
if (not options.host_ip or not options.image):
|
||||||
|
logging.critical("Not enough arguments.")
|
||||||
|
|
||||||
|
return 1
|
||||||
|
# end if
|
||||||
|
|
||||||
|
if not os.path.exists(options.image):
|
||||||
|
logging.critical('Sorry: the file %s does not exist', options.image)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
# end if
|
||||||
|
|
||||||
|
upload(options.host_ip, options.host_port, options.image)
|
||||||
|
# end main
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv))
|
||||||
|
# end if
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,130 @@
|
||||||
|
|
||||||
|
# ESP8266 platform
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
# For more info:
|
||||||
|
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
|
||||||
|
|
||||||
|
name=ESP8266 Modules
|
||||||
|
version=2.2.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
compiler.warning_flags=-w
|
||||||
|
compiler.warning_flags.none=-w
|
||||||
|
compiler.warning_flags.default=
|
||||||
|
compiler.warning_flags.more=-Wall
|
||||||
|
compiler.warning_flags.all=-Wall -Wextra
|
||||||
|
|
||||||
|
build.lwip_lib=-llwip_gcc
|
||||||
|
build.lwip_flags=-DLWIP_OPEN_SRC
|
||||||
|
|
||||||
|
compiler.path={runtime.tools.xtensa-lx106-elf-gcc.path}/bin/
|
||||||
|
compiler.sdk.path={runtime.platform.path}/tools/sdk
|
||||||
|
compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include" "-I{compiler.sdk.path}/lwip/include" "-I{build.path}/core"
|
||||||
|
|
||||||
|
compiler.c.cmd=xtensa-lx106-elf-gcc
|
||||||
|
compiler.c.flags=-c {compiler.warning_flags} -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections
|
||||||
|
|
||||||
|
compiler.S.cmd=xtensa-lx106-elf-gcc
|
||||||
|
compiler.S.flags=-c -g -x assembler-with-cpp -MMD -mlongcalls
|
||||||
|
|
||||||
|
compiler.c.elf.flags=-g {compiler.warning_flags} -Os -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-T{build.flash_ld}" -Wl,--gc-sections -Wl,-wrap,system_restart_local -Wl,-wrap,register_chipv6_phy
|
||||||
|
|
||||||
|
compiler.c.elf.cmd=xtensa-lx106-elf-gcc
|
||||||
|
compiler.c.elf.libs=-lm -lgcc -lhal -lphy -lpp -lnet80211 -lwpa -lcrypto -lmain -lwps -laxtls -lsmartconfig -lmesh -lwpa2 {build.lwip_lib} -lstdc++
|
||||||
|
|
||||||
|
compiler.cpp.cmd=xtensa-lx106-elf-g++
|
||||||
|
compiler.cpp.flags=-c {compiler.warning_flags} -Os -g -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD -ffunction-sections -fdata-sections
|
||||||
|
|
||||||
|
compiler.as.cmd=xtensa-lx106-elf-as
|
||||||
|
|
||||||
|
compiler.ar.cmd=xtensa-lx106-elf-ar
|
||||||
|
compiler.ar.flags=cru
|
||||||
|
|
||||||
|
compiler.elf2hex.cmd=esptool
|
||||||
|
compiler.elf2hex.flags=
|
||||||
|
|
||||||
|
compiler.size.cmd=xtensa-lx106-elf-size
|
||||||
|
|
||||||
|
compiler.esptool.cmd=esptool
|
||||||
|
compiler.esptool.cmd.windows=esptool.exe
|
||||||
|
|
||||||
|
# This can be overriden in boards.txt
|
||||||
|
build.extra_flags=-DESP8266
|
||||||
|
|
||||||
|
# These can be overridden in platform.local.txt
|
||||||
|
compiler.c.extra_flags=
|
||||||
|
compiler.c.elf.extra_flags=
|
||||||
|
compiler.S.extra_flags=
|
||||||
|
compiler.cpp.extra_flags=
|
||||||
|
compiler.ar.extra_flags=
|
||||||
|
compiler.objcopy.eep.extra_flags=
|
||||||
|
compiler.elf2hex.extra_flags=
|
||||||
|
|
||||||
|
## generate file with git version number
|
||||||
|
## needs bash, git, and echo
|
||||||
|
|
||||||
|
## windows-compatible version may be added later
|
||||||
|
|
||||||
|
|
||||||
|
## Compile c files
|
||||||
|
recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.c.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
|
||||||
|
|
||||||
|
## Compile c++ files
|
||||||
|
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
|
||||||
|
|
||||||
|
## Compile S files
|
||||||
|
recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
|
||||||
|
|
||||||
|
## Create archives
|
||||||
|
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/arduino.ar" "{object_file}"
|
||||||
|
|
||||||
|
## Combine gc-sections, archives, and objects
|
||||||
|
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{build.path}/arduino.ar" {compiler.c.elf.libs} -Wl,--end-group "-L{build.path}"
|
||||||
|
|
||||||
|
## Create eeprom
|
||||||
|
recipe.objcopy.eep.pattern=
|
||||||
|
|
||||||
|
## Create hex
|
||||||
|
#recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex"
|
||||||
|
|
||||||
|
recipe.objcopy.hex.pattern="{runtime.tools.esptool.path}/{compiler.esptool.cmd}" -eo "{runtime.platform.path}/bootloaders/eboot/eboot.elf" -bo "{build.path}/{build.project_name}.bin" -bm {build.flash_mode} -bf {build.flash_freq} -bz {build.flash_size} -bs .text -bp 4096 -ec -eo "{build.path}/{build.project_name}.elf" -bs .irom0.text -bs .text -bs .data -bs .rodata -bc -ec
|
||||||
|
|
||||||
|
## Save hex
|
||||||
|
recipe.output.tmp_file={build.project_name}.bin
|
||||||
|
recipe.output.save_file={build.project_name}.{build.variant}.bin
|
||||||
|
|
||||||
|
## Compute size
|
||||||
|
recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf"
|
||||||
|
recipe.size.regex=^(?:\.irom0\.text|\.text|\.data|\.rodata|)\s+([0-9]+).*
|
||||||
|
recipe.size.regex.data=^(?:\.data|\.rodata|\.bss)\s+([0-9]+).*
|
||||||
|
#recipe.size.regex.eeprom=^(?:\.eeprom)\s+([0-9]+).*
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
tools.esptool.cmd=esptool
|
||||||
|
tools.esptool.cmd.windows=esptool.exe
|
||||||
|
tools.esptool.path={runtime.tools.esptool.path}
|
||||||
|
tools.esptool.network_cmd=python
|
||||||
|
tools.esptool.network_cmd.windows=python.exe
|
||||||
|
|
||||||
|
tools.esptool.upload.protocol=esp
|
||||||
|
tools.esptool.upload.params.verbose=-vv
|
||||||
|
tools.esptool.upload.params.quiet=
|
||||||
|
tools.esptool.upload.pattern="{path}/{cmd}" {upload.verbose} -cd {upload.resetmethod} -cb {upload.speed} -cp "{serial.port}" -ca 0x00000 -cf "{build.path}/{build.project_name}.bin"
|
||||||
|
tools.esptool.upload.network_pattern="{network_cmd}" "{runtime.platform.path}/tools/espota.py" -i "{serial.port}" -p "{network.port}" "--auth={network.password}" -f "{build.path}/{build.project_name}.bin"
|
||||||
|
|
||||||
|
tools.mkspiffs.cmd=mkspiffs
|
||||||
|
tools.mkspiffs.cmd.windows=mkspiffs.exe
|
||||||
|
tools.mkspiffs.path={runtime.tools.mkspiffs.path}
|
||||||
|
|
||||||
|
tools.espupload.cmd=python
|
||||||
|
tools.espupload.cmd.windows=python.exe
|
||||||
|
tools.espupload.path={runtime.platform.path}/tools
|
||||||
|
|
||||||
|
tools.espupload.upload.protocol=espupload
|
||||||
|
tools.espupload.upload.params.verbose=
|
||||||
|
tools.espupload.upload.params.quiet=
|
||||||
|
tools.espupload.upload.pattern="{cmd}" "{path}/espupload.py" -f "{build.path}/{build.project_name}.bin"
|
|
@ -0,0 +1,33 @@
|
||||||
|
## Sonoff-MQTT-OTA-Arduino - TASMOTA NextGen
|
||||||
|
Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE.
|
||||||
|
|
||||||
|
Current version is **3.9.4** - See ```_releasenotes.ino``` for change information.
|
||||||
|
|
||||||
|
- This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic.
|
||||||
|
- Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```.
|
||||||
|
- After reboot select config menu again or use commands ```GPIOs``` and ```GPIO``` to change GPIO with desired sensor.
|
||||||
|
- Some features still need to be ironed out.
|
||||||
|
|
||||||
|
<img alt="Sonoff" src="https://github.com/arendst/arendst.github.io/blob/master/media/sonoffbasic.jpg" width="250" align="right" />
|
||||||
|
See [Wiki](https://github.com/arendst/Sonoff-MQTT-OTA-Arduino/wiki) for more information.<br />
|
||||||
|
See [Community](https://groups.google.com/d/forum/sonoffusers) for forum and more user experience.
|
||||||
|
|
||||||
|
Starting with version 2.0.0 the following devices are supported:
|
||||||
|
- [iTead Sonoff Basic](http://sonoff.itead.cc/en/products/sonoff/sonoff-basic)
|
||||||
|
- [iTead Sonoff RF](http://sonoff.itead.cc/en/products/sonoff/sonoff-rf)
|
||||||
|
- [iTead Sonoff SV](https://www.itead.cc/sonoff-sv.html)
|
||||||
|
<img alt="Sonoff" src="https://github.com/arendst/arendst.github.io/blob/master/media/sonoff_th.jpg" width="250" align="right" />
|
||||||
|
- [iTead Sonoff TH10/TH16 with temperature sensor](http://sonoff.itead.cc/en/products/sonoff/sonoff-th)
|
||||||
|
- [iTead Sonoff Dual](http://sonoff.itead.cc/en/products/sonoff/sonoff-dual)
|
||||||
|
- [iTead Sonoff Pow](http://sonoff.itead.cc/en/products/sonoff/sonoff-pow)
|
||||||
|
- [iTead Sonoff 4CH](http://sonoff.itead.cc/en/products/sonoff/sonoff-4ch)
|
||||||
|
- [iTead S20 Smart Socket](http://sonoff.itead.cc/en/products/residential/s20-socket)
|
||||||
|
- [iTead Slampher](http://sonoff.itead.cc/en/products/residential/slampher-rf)
|
||||||
|
- [iTead Sonoff Touch](http://sonoff.itead.cc/en/products/residential/sonoff-touch)
|
||||||
|
- [iTead Sonoff Led](http://sonoff.itead.cc/en/products/appliances/sonoff-led)
|
||||||
|
- [iTead 1 Channel Switch 5V / 12V](https://www.itead.cc/smart-home/inching-self-locking-wifi-wireless-switch.html)
|
||||||
|
- [iTead Motor Clockwise/Anticlockwise](https://www.itead.cc/smart-home/motor-reversing-wifi-wireless-switch.html)
|
||||||
|
- [Electrodragon IoT Relay Board](http://www.electrodragon.com/product/wifi-iot-relay-board-based-esp8266/)
|
||||||
|
|
||||||
|
<img alt="Sonoff" src="https://github.com/arendst/arendst.github.io/blob/master/media/sonofftoucheu.jpg" height="280" align="left" />
|
||||||
|
<img alt="Sonoff" src="https://github.com/arendst/arendst.github.io/blob/master/media/sonoff4ch.jpg" height="250" align="right" />
|
|
@ -0,0 +1,514 @@
|
||||||
|
/* 3.9.4 20170127
|
||||||
|
* Fix Sonoff Dual Relay switching (#287)
|
||||||
|
*
|
||||||
|
* 3.9.3 20170127
|
||||||
|
* Add confirmation before Restart via webpage
|
||||||
|
* Expand Domoticz Configuration webpage with Key, Switch and Sensor Index and
|
||||||
|
* add commands DomoticzSwitchIdx and DomoticzSensorIdx (#86) (#174) (#219)
|
||||||
|
* Fix default DHT11 sensor driver selection
|
||||||
|
* Fix LedPower status after button press (#279)
|
||||||
|
* Add command Sleep 0 - 250 mSec for optional light sleep mode to lower energy consumption (#272)
|
||||||
|
* (Expect overall button/key/switch misses and wrong values on Sonoff Pow)
|
||||||
|
* Add Hue brightness extension (#281)
|
||||||
|
* Fix Hue brightness and change to call by reference (#283)
|
||||||
|
*
|
||||||
|
* 3.9.2 20170124
|
||||||
|
* Add confirmation before Reset Configuration via webpage (#244)
|
||||||
|
* Add WS2812 features (see Wiki commands)
|
||||||
|
*
|
||||||
|
* 3.9.1 20170124
|
||||||
|
* Change PowerOnState function to only trigger when Power On (and not just restart) (#238)
|
||||||
|
* Move HLW interrupts back to RAM and make WS2812_DMA optional as it generates Exception on Pow (#264)
|
||||||
|
* Add charset=utf-8 to webpages (#266)
|
||||||
|
* Update Hue emulation (#268)
|
||||||
|
* Fix status module number
|
||||||
|
* Add support for domoticz Dimmer on Sonoff_Led and WS2812
|
||||||
|
* Fix possible ESP8285 flash problem by updating Flash Chip Mode to DOUT during web upload
|
||||||
|
*
|
||||||
|
* 3.2.6a 20170120
|
||||||
|
* Fix Sonoff Pow compile error (#255)
|
||||||
|
* Move HLW interrupts back to ROM (Needed for WS2812 DMA interrupts)
|
||||||
|
* Removed all IO config from user_config.h as this will be done by commands or webpage
|
||||||
|
* Removed MessageFormat and supports JSON only except POWER/LIGHT status
|
||||||
|
* Add command LedPower to control main led (#247)
|
||||||
|
* Add more FriendlyNames for Hue (#254)
|
||||||
|
* Add DMA support for WS2812 when using pin 3 while other pins work just as well in my case...
|
||||||
|
* Add HUE emulation for Alexa (#229)
|
||||||
|
* Add basic WS2812 support (#229)
|
||||||
|
* Fix Wemo when MQTT is disabled (#245)
|
||||||
|
* Revert ButtonTopic and change SwitchTopic1 - 4 to one SwitchTopic
|
||||||
|
* Rename MqttUnits to Units
|
||||||
|
* Add Mqtt command to enable/disable MQTT
|
||||||
|
*
|
||||||
|
* 3.2.2a 20170115
|
||||||
|
* Add dynamic (Sonoff) Module, user GPIO and sensor selection (one size fits (almost) all)
|
||||||
|
* Add support for Sonoff LED
|
||||||
|
* Add Seriallog disable after 600 seconds for Sonoff Dual and 4 Channel
|
||||||
|
* Add ButtonTopic2 - 4, SwitchTopic1 - 4 and SwitchRetain
|
||||||
|
*
|
||||||
|
* 3.2.2 20170113
|
||||||
|
* Fix PowerOnState 2 functionality after re-applying power (#230)
|
||||||
|
*
|
||||||
|
* 3.2.1 20170113
|
||||||
|
* Fix some failed command decoding (#228)
|
||||||
|
* Removed passwords from status messages (#216)
|
||||||
|
*
|
||||||
|
* 3.2.0 20170111
|
||||||
|
* Add I2C BH1750 sensor (#222)
|
||||||
|
* Sensor rewrite preparing for online selection
|
||||||
|
*
|
||||||
|
* 3.1.16 20170109
|
||||||
|
* Fix Domoticz possible error condition
|
||||||
|
* Remove Wifi password from connection message (#216)
|
||||||
|
* Add Configure Other menu item to web page (#209)
|
||||||
|
* Add command FriendlyName, field Friendly Name and define FRIENDLY_NAME to be used by Alexa
|
||||||
|
* eliminating current use of MQTT_CLIENT_ID (#209)
|
||||||
|
* Add friendlyname to webpage replacing former hostname
|
||||||
|
*
|
||||||
|
* 3.1.15 20170108
|
||||||
|
* Fix Domoticz send key regression with Toggle command
|
||||||
|
*
|
||||||
|
* 3.1.14 20170107
|
||||||
|
* Add support for command TOGGLE (define MQTT_CMND_TOGGLE) when ButtonTopic is in use and not equal to Topic (#207)
|
||||||
|
*
|
||||||
|
* 3.1.13 20170107
|
||||||
|
* Fix web console command input when SUB_PREFIX contains '/' (#152)
|
||||||
|
* Add command response to web command (#200)
|
||||||
|
* Add option to disable MQTT as define USE_MQTT in user_config.h (#200)
|
||||||
|
*
|
||||||
|
* 3.1.12 20170106
|
||||||
|
* Add OTA retry to solve possible HTTP transient errors (#204)
|
||||||
|
* Fix MQTT host discovery
|
||||||
|
*
|
||||||
|
* 3.1.11 20170105
|
||||||
|
* Add mDNS to advertise webserver as <hostname>.local/
|
||||||
|
*
|
||||||
|
* 3.1.10 20170105
|
||||||
|
* Fix ButtonTopic when SUB_PREFIX = PUB_PREFIX
|
||||||
|
* Add workaround for possible MQTT queueing when SUB_PREFIX = PUB_PREFIX
|
||||||
|
* Add optional MQTT host discovery using define USE_DISCOVERY in user_config.h (#115)
|
||||||
|
*
|
||||||
|
* 3.1.9 20170104
|
||||||
|
* Fix Power Blink start position (toggled)
|
||||||
|
* Change PulseTime increments: 1 .. 111 in 0.1 sec (max 11 seconds) and 112 .. 64900 in seconds (= 12 seconds until 18 hours) (#188)
|
||||||
|
* Add support for SUB_PREFIX = PUB_PREFIX (#190)
|
||||||
|
*
|
||||||
|
* 3.1.8 20170103
|
||||||
|
* Add retain flag to LWT offline and only send "tele/sonoff/LWT Offline" (#179)
|
||||||
|
* Change retained LWT Online message to only send "tele/sonoff/LWT Online"
|
||||||
|
*
|
||||||
|
* 3.1.7 20161231
|
||||||
|
* Add retained message LWT Online when sonoff makes MQTT connection (#179)
|
||||||
|
*
|
||||||
|
* 3.1.6 20161230
|
||||||
|
* Add blinking using commands BlinkTime, BlinkCount and Power Blink|3|BlinkOff|4 (#165)
|
||||||
|
*
|
||||||
|
* 3.1.5 20161228
|
||||||
|
* Fix serial space command exception (28)
|
||||||
|
*
|
||||||
|
* 3.1.4 20161227
|
||||||
|
* Fix MQTT subscribe regression exception (3) (#162)
|
||||||
|
* Fix serial empty command exception (28)
|
||||||
|
*
|
||||||
|
* 3.1.3 20161225
|
||||||
|
* Extent Domoticz configuration webpage with optional indices (#153)
|
||||||
|
* Fix multi relay legacy tele message from tele/sonoff/2/POWER to tele/sonoff/POWER2
|
||||||
|
* Add support for iTead Motor Clockwise/Anticlockwise
|
||||||
|
*
|
||||||
|
* 3.1.2 20161224
|
||||||
|
* Extent command PowerOnState with toggle at power on (option 2 is now option 3!) (#156)
|
||||||
|
*
|
||||||
|
* 3.1.1 20161223
|
||||||
|
* Add support for Sonoff Touch and Sonoff 4CH (#40)
|
||||||
|
* Update DomoticzIdx and DomoticzKeyIdx with relay/key index (DomoticzIdx1/DomoticzKeyIdx1)
|
||||||
|
* Add command PowerOnState to control relay(s) at power on (#154)
|
||||||
|
*
|
||||||
|
* 3.1.0 20161221
|
||||||
|
* Add Sonoff Pow measurement smoothing
|
||||||
|
* Fix serial command topic preamble error (#151)
|
||||||
|
* Fix 2.x to 3.x migration inconsistencies (#146)
|
||||||
|
*
|
||||||
|
* 3.0.9 20161218
|
||||||
|
* Add Sonoff Pow voltage reading when relay is on but no load present (#123)
|
||||||
|
*
|
||||||
|
* 3.0.8 20161218
|
||||||
|
* Add temperature conversion to Fahrenheit as option in user_config.h (TEMP_CONVERSION) (#145)
|
||||||
|
*
|
||||||
|
* 3.0.7 20161217
|
||||||
|
* Add user_config_override.h to be used by user to override some defaults in user_config.h (#58)
|
||||||
|
* Fix Sonoff Pow low power (down to 4W) intermittent measurements (#123)
|
||||||
|
*
|
||||||
|
* 3.0.6 20161217
|
||||||
|
* Fix MQTT_CLIENT_ID starting with % sign as in "%06X" (#142)
|
||||||
|
* Add auto power off after PulseTime * 0.1 Sec to relay 1 (#134)
|
||||||
|
*
|
||||||
|
* 3.0.5 20161215
|
||||||
|
* Add more control over LED with command LedState options (#136, #143)
|
||||||
|
* LED_OFF (0), LED_POWER (1), LED_MQTTSUB (2), LED_POWER_MQTTSUB (3), LED_MQTTPUB (4), LED_POWER_MQTTPUB (5), LED_MQTT (6), LED_POWER_MQTT (7)
|
||||||
|
* Add option WIFI_RETRY (4) to command WifiConfig to allow connection retry to other AP without restart (#73)
|
||||||
|
*
|
||||||
|
* 3.0.4 20161211
|
||||||
|
* Fix intermittent Domoticz update misses (#133)
|
||||||
|
*
|
||||||
|
* 3.0.3 20161210
|
||||||
|
* Fix compiler warnings (#132)
|
||||||
|
* Remove redundant code
|
||||||
|
* Fix Domoticz pushbutton support
|
||||||
|
*
|
||||||
|
* 3.0.2 20161209
|
||||||
|
* Add pushbutton to SwitchMode (#130)
|
||||||
|
*
|
||||||
|
* 3.0.1 20161209
|
||||||
|
* Fix initial config
|
||||||
|
*
|
||||||
|
* 3.0.0 20161208
|
||||||
|
* Migrate and clean-up flash layout
|
||||||
|
* Settings from version 2.x are saved but settings from version 3.x can not be used with version 2.x
|
||||||
|
* Change SEND_TELEMETRY_RSSI to SEND_TELEMETRY_WIFI and add AP and SSID to telemetry
|
||||||
|
* Split long JSON messages
|
||||||
|
* Fix inconsistent status messages
|
||||||
|
* Fix all status messages to return JSON if enabled
|
||||||
|
* Remove relay index in cmnd/sonoff/<relay>/POWER now changed
|
||||||
|
* to cmnd/sonoff/POWER for single relay units
|
||||||
|
* and cmnd/sonoff/POWER<relay> for multi relay units like Sonoff dual
|
||||||
|
* Add retain option to Power/Light status controlled by command PowerRetain On|Off (#126)
|
||||||
|
*
|
||||||
|
* 2.1.2 20161204
|
||||||
|
* Add support for second wifi AP (#73)
|
||||||
|
* Update command WifiConfig
|
||||||
|
* Fix possible WifiManager hang
|
||||||
|
*
|
||||||
|
* 2.1.1a 20161203
|
||||||
|
* Fix scan for wifi networks if WeMo is enabled
|
||||||
|
* Fix syslog setting using web page
|
||||||
|
*
|
||||||
|
* 2.1.1 20161202
|
||||||
|
* Add support for ElectroDragon second relay and button (only toggle with optional ButtonTopic) (#110)
|
||||||
|
*
|
||||||
|
* 2.1.0 20161202
|
||||||
|
* Add optional EXPERIMENTAL TLS to MQTT (#49)
|
||||||
|
* Fix MQTT payload handling (#111)
|
||||||
|
* Optimzed WeMo code
|
||||||
|
*
|
||||||
|
* 2.0.21a 20161201
|
||||||
|
* Fix WeMo PowerPlug emulation
|
||||||
|
*
|
||||||
|
* 2.0.21 20161130
|
||||||
|
* Add Belkin WeMo PowerPlug emulation enabled with USE_WEMO_EMULATION in user_config.h (Heiko Krupp) (#105, #109)
|
||||||
|
*
|
||||||
|
* 2.0.20 20161130
|
||||||
|
* Relax MQTTClient naming but only allows hexadecimal uppercase numbers (#107)
|
||||||
|
* Add I2C support with command I2CScan
|
||||||
|
* Add I2C sensor driver for HTU21 as alternate sensor using TH10/16 connectors (Heiko Krupp) (#105)
|
||||||
|
* Add I2C sensor driver for BMP085/BMP180/BMP280/BME280 as alternate sensor using TH10/16 connectors
|
||||||
|
*
|
||||||
|
* 2.0.19a 20161127
|
||||||
|
* Add support for ButtonTopic and ButtonRetain to wall switch function
|
||||||
|
* Add pullup to SWITCH_PIN and command SwitchMode to syntax
|
||||||
|
*
|
||||||
|
* 2.0.18 20161126
|
||||||
|
* Add SUB_PREFIX multi level support allowing 'cmnd' or 'cmnd/level2/level3'
|
||||||
|
* Add wall switch function to GPIO14 and command SwitchMode (Alex Scott) (#103)
|
||||||
|
*
|
||||||
|
* 2.0.17 20161123
|
||||||
|
* Calibrate HLWPCAL from 12345 to 12530
|
||||||
|
* Add alternative sensor driver DHT2 using Adafruit DHT library
|
||||||
|
* Add define MESSAGE_FORMAT to user_config.h
|
||||||
|
* Throttle console messages
|
||||||
|
* Shorten JSON messages
|
||||||
|
* Fix possible Panic
|
||||||
|
* Fix User mode webserver security
|
||||||
|
*
|
||||||
|
* 2.0.16 20161118
|
||||||
|
* Add alternative sensor driver DS18x20 using OneWire library (#95)
|
||||||
|
* Change sensor MQTT message from tele/sonoff/TEMPERATURE to tele/sonoff/DHT/TEMPERATURE or
|
||||||
|
* tele/sonoff/DS18B20/TEMPERATURE or tele/sonoff/DS18x20/1/TEMPERATURE
|
||||||
|
* Add sensors to root webpage and auto refresh every 4 seconds (#92)
|
||||||
|
* Add optional JSON messageformat to all telemetry data
|
||||||
|
* Enforce minimum TelePeriod to be 10 seconds
|
||||||
|
* Fix Energy Yesterday reset after restart
|
||||||
|
* Add Energy Today restore after controlled restart
|
||||||
|
*
|
||||||
|
* 2.0.15 20161116
|
||||||
|
* Change TODAY_POWER and PERIOD_POWER to TODAY_ENERGY and PERIOD_ENERGY
|
||||||
|
* Fix serial regression
|
||||||
|
* Fix syslog hangs when loghost is unavailable
|
||||||
|
*
|
||||||
|
* 2.0.14 20161115
|
||||||
|
* Add HLW threshold delay
|
||||||
|
* Fix HLW intermittent current deviation
|
||||||
|
* Fix button functionality during wificonfig
|
||||||
|
* Add CRC check to DS18B20 sensor (#88)
|
||||||
|
*
|
||||||
|
* 2.0.13 20161113
|
||||||
|
* Add additional upload error code descriptions
|
||||||
|
* Add PlatformIO support (#80)
|
||||||
|
*
|
||||||
|
* 2.0.12 20161113
|
||||||
|
* Fix Serial and Web response regression when no MQTT connection available
|
||||||
|
* Fix Sonoff Dual power telemetric data for second relay
|
||||||
|
* Removed MQTT password from Information web page
|
||||||
|
* Hide MQTT password from Configure MQTT web page
|
||||||
|
*
|
||||||
|
* 2.0.11 20161111
|
||||||
|
* Rewrite button and web toggle code
|
||||||
|
* Fix NTP sync
|
||||||
|
* Add HLW calibration commands HLWPCAL, HLWUCAL and HLWICAL (need define USE_POWERCALIBRATION)
|
||||||
|
* Fix power threshold tests
|
||||||
|
*
|
||||||
|
* 2.0.10 20161109
|
||||||
|
* Add additional Domoticz define (#63)
|
||||||
|
* Add defines MQTT_STATUS_ON and MQTT_STATUS_OFF in user_config.h to select status On/Off string
|
||||||
|
* Fix status response differences (#65)
|
||||||
|
* Fix divide by zero exception (#70)
|
||||||
|
* Fix syslog loop exception
|
||||||
|
*
|
||||||
|
* 2.0.9 20161108
|
||||||
|
* clarify MODULE in user_config.h
|
||||||
|
* Fix hlw false values
|
||||||
|
*
|
||||||
|
* 2.0.8 20161108
|
||||||
|
* Add initial status after power on
|
||||||
|
* Seperate driver files
|
||||||
|
* Fix hlw code and calibrate Pow
|
||||||
|
* Move user config defines to user_config.h (#61)
|
||||||
|
*
|
||||||
|
* 2.0.7 20161030
|
||||||
|
* Make Ticker mandatory
|
||||||
|
* Add Domoticz support (Increase MQTT_MAX_PACKET_SIZE to 400) (#54)
|
||||||
|
* Add command MessageFormat 0|1 to select either legacy or JSON output
|
||||||
|
*
|
||||||
|
* 2.0.6 20161024
|
||||||
|
* Add Sonoff Pow power factor
|
||||||
|
* Initial support for up to four relays using iTEAD PSB (4Channel)
|
||||||
|
* - Currently only supports one button (All buttons behave the same)
|
||||||
|
* - Use command MODEL 4 to select four relay option
|
||||||
|
* (After first power on it will support 2 relays like Sonoff Dual)
|
||||||
|
* Fix ledstate
|
||||||
|
* Add command Status 9 to display Sonoff Pow thresholds
|
||||||
|
* Add commands PowerLow, PowerHigh, VoltageLow, VoltageHigh, CurrentLow and CurrentHigh for use
|
||||||
|
* with Sonoff Pow thresholds
|
||||||
|
*
|
||||||
|
* 2.0.5 20161018
|
||||||
|
* Add updates to user_config.h - moved SEND_TELEMETRY_DS18B20 and SEND_TELEMETRY_DHT to module area.
|
||||||
|
* As Sonoff TH10/16 does not have the logic installed for GPIO04 You'll have to select ONE of both
|
||||||
|
* Add Sonoff Pow support (experimental until Pow tested)
|
||||||
|
* Add command Status 8 to display Sonoff Pow energy values
|
||||||
|
* Add command MqttUnits On|Off to add units to values
|
||||||
|
* Change web main page header character size
|
||||||
|
* Change On/Off to ON/OFF status messages to satisfy openHAB
|
||||||
|
* Change TEMP to TEMPERATURE and HUM to HUMIDITY
|
||||||
|
*
|
||||||
|
* 2.0.4 20161009
|
||||||
|
* Add MQTT_BUTTON_RETAIN, SAVE_DATA and SAVE_STATE defines to user_config.h (#35)
|
||||||
|
* Update ButtonRetain to remove retained message(s) from broker when turned off
|
||||||
|
* Add Retain for second relay on Sonoff Dual
|
||||||
|
* Provide power status messages with device topic index if requested
|
||||||
|
*
|
||||||
|
* 2.0.3 20161008
|
||||||
|
* Update wifi initialization
|
||||||
|
* Add command BUTTONRETAIN for optional MQTT retain on button press (#35)
|
||||||
|
* Add command SAVESTATE to disable power state save. May be used with MQTT retain
|
||||||
|
*
|
||||||
|
* 2.0.2 20161006
|
||||||
|
* Fix wifi issue 2186
|
||||||
|
*
|
||||||
|
* 2.0.1 20161002
|
||||||
|
* Fix button press
|
||||||
|
*
|
||||||
|
* 2.0.0 20161002
|
||||||
|
* Update Sonoff TH10/16 sensor pins (My TH10 only has GPIO14 connected)
|
||||||
|
* Add full support for Sonoff dual
|
||||||
|
*
|
||||||
|
* 1.0.35 20160929
|
||||||
|
* Add more lines to console
|
||||||
|
* Add timeout and disable MQTT on web upload
|
||||||
|
* Add command SAVEDATA to control parameter save (for flash wear afficionados) (#30)
|
||||||
|
*
|
||||||
|
* 1.0.34 20160926
|
||||||
|
* Fix button press six and seven
|
||||||
|
* Add more information to webserver
|
||||||
|
*
|
||||||
|
* 1.0.33 20160915
|
||||||
|
* Better WPS error message
|
||||||
|
* Separate webserver code from support.ino into webserver.ino
|
||||||
|
* Fix webserver User by removing unwanted restart option
|
||||||
|
*
|
||||||
|
* 1.0.32 20160913
|
||||||
|
* Add Wifi Protected Setup (WPS) as third option for initial config
|
||||||
|
* Add command WIFICONFIG replacing deprecated command SMARTCONFIG
|
||||||
|
* Add option WIFICONFIG 3 to start WPSconfig
|
||||||
|
* Add option WIFICONFIG 0 to start saved Wifi config tool (WPSconfig, Smartconfig or Wifimanager)
|
||||||
|
* Change button behaviour - See Wiki
|
||||||
|
*
|
||||||
|
* 1.0.31 20160907
|
||||||
|
* Fix DS18B20 misread if teleperiod = 2
|
||||||
|
* Tuned sensor code
|
||||||
|
* Updated prefered ElectroDragon connection to Relay 1 and Button 1
|
||||||
|
* Moved SONOFF and ELECTRO_DRAGON port config to user_config.h
|
||||||
|
*
|
||||||
|
* 1.0.30 20160902
|
||||||
|
* Fix command TELEPERIOD 0
|
||||||
|
* Add ESP- tag to UDP log message for easy rsyslogd filtering
|
||||||
|
* Add ElectroDragon (Relay 2 only) functionality. Select with #define MODULE ELECTRO_DRAGON
|
||||||
|
* Add ? as null message alternative
|
||||||
|
* Add DHT temperature and humidity telemetry support. Enable with #define SEND_TELEMETRY_DHT
|
||||||
|
* Add DS18B20 temperature telemetry support. Enable with #define SEND_TELEMETRY_DS18B20
|
||||||
|
* Restrict HOSTNAME, MQTTCLIENT, TOPIC and BUTTONTOPIC in topic mode only
|
||||||
|
*
|
||||||
|
* 1.0.29 20160831
|
||||||
|
* Allow UPGRADE, OTAURL, RESTART, RESET, MQTTHOST, MQTTPORT, MQTTUSER, MQTTPASSWORD and WEBSERVER also in group mode
|
||||||
|
*
|
||||||
|
* 1.0.28 20160831
|
||||||
|
* Add webserver state to status 5
|
||||||
|
* Add optional PUB_PREFIX2 (tele) for telemetry usage
|
||||||
|
* Add command TELEPERIOD
|
||||||
|
* Fix syntax message
|
||||||
|
* Change memory status display
|
||||||
|
*
|
||||||
|
* 1.0.27 20160831
|
||||||
|
* Add sketch flash size
|
||||||
|
* Add console to webserver
|
||||||
|
* Add command weblog
|
||||||
|
* Change WifiManager web pages to minimal
|
||||||
|
* Change display default hostname and MQTT client id in webserver
|
||||||
|
* Change HTTP command interface to http://sonoff-1234/cm?cmnd=light 2
|
||||||
|
* Change HEARTBEAT to UPTIME
|
||||||
|
*
|
||||||
|
* 1.0.26 20160829
|
||||||
|
* Add define USE_WEBSERVER to disable web server code in source
|
||||||
|
* Add file upload as alternative for ota upload to webserver
|
||||||
|
* Add information to webserver
|
||||||
|
* Add command hostname
|
||||||
|
* Add command logport
|
||||||
|
* Change HTTP command interface to http://sonoff-1234/cmd?cmnd=light 2
|
||||||
|
* Change button behaviour with regards to Smartconfig and OTA upload. See README.md
|
||||||
|
* Enforce default hostname to either "%s-%04d" or user defined without any %
|
||||||
|
* Enforce default mqtt client id to either "DVES_%06X" or user defined without any %
|
||||||
|
*
|
||||||
|
* 1.0.25 20160822
|
||||||
|
* Remove config system halts to keep ota available
|
||||||
|
*
|
||||||
|
* 1.0.24 20160821
|
||||||
|
* Add test for MQTT_SUBTOPIC
|
||||||
|
* Change log range to LOG_LEVEL_ALL
|
||||||
|
* Change MQTT introduction messages
|
||||||
|
* Moved MQTT_MAX_PACKET_SIZE warning message to introduction messages
|
||||||
|
*
|
||||||
|
* 1.0.23 20160821
|
||||||
|
* Add option USE_SPIFFS to move config from flash to spiffs
|
||||||
|
* Add webserver with options 0 (off), 1 (user) and 2 (admin)
|
||||||
|
* Add HTTP command interface (http://sonoff-1234/c?cmnd=light 2)
|
||||||
|
* Add wifimanager countdown counter
|
||||||
|
* Add command line webpage
|
||||||
|
* Add relay control to wifimanager
|
||||||
|
* Add restart option 99 to force restart
|
||||||
|
* Fix wifi hostname
|
||||||
|
* Fix NETBIOS hostname problem by reducing default hostname length
|
||||||
|
* Fix possible exception if WIFI_HOSTNAME is changed
|
||||||
|
* Fix upgrade messages
|
||||||
|
* Reduce memory use by redesigning config routines
|
||||||
|
* Split syntax message
|
||||||
|
* Rename define SERIAL_IO to USE_SERIAL
|
||||||
|
*
|
||||||
|
* 1.0.22 20160814
|
||||||
|
* Add all MQTT parameters for configuration
|
||||||
|
* Add wifimanager to configure Wifi and MQTT via web server
|
||||||
|
* Change NTP time handling
|
||||||
|
* Fix Smartconfig parameter buffer overflow
|
||||||
|
* Fix PlatformIO warnings
|
||||||
|
*
|
||||||
|
* 1.0.21 20160808
|
||||||
|
* Remove semaphore as subscription flooding (more than 15 subscriptions per second) is managed by SDK (LmacRxBlk:1)
|
||||||
|
* Add optional RTC interrupt (define USE_TICKER) to keep RTC synced during subscription flooding
|
||||||
|
* Remove heartbeatflag
|
||||||
|
*
|
||||||
|
* 1.0.20 20160805
|
||||||
|
* Add semaphore to handle out of memory when too many subscriptions requested
|
||||||
|
* Use Daylight Saving (DST) parameters from user_config.h when timezone = 99
|
||||||
|
* Add status 7 option displaying RTC information
|
||||||
|
* Add ledstate to status 0
|
||||||
|
*
|
||||||
|
* 1.0.19 20160803
|
||||||
|
* Fix possible MQTT_CLIENT_ID induced Exception(28)
|
||||||
|
*
|
||||||
|
* 1.0.18 20160803
|
||||||
|
* Moved Cfg_Default
|
||||||
|
* Fix negative data handling
|
||||||
|
* Remove MQTT information from status 1 and add labels to status 1
|
||||||
|
* Add mac address to status 5
|
||||||
|
* Add MQTT ClientId, UserId and Password to status 6
|
||||||
|
*
|
||||||
|
* 1.0.17 20160731
|
||||||
|
* Better variable range checking
|
||||||
|
* Change ambiguous connection messages
|
||||||
|
* Add timestamp to serial message
|
||||||
|
*
|
||||||
|
* 1.0.16 20160729
|
||||||
|
* Moved wifi, rtc, syslog and config to support.ino
|
||||||
|
* Fixed button action when buttontopic is used. Introduced with 1.0.15
|
||||||
|
* Better buffer overflow checks (strlcpy)
|
||||||
|
*
|
||||||
|
* 1.0.15 20160728
|
||||||
|
* Removed pubsubclient config changes from sonoff.ino as it doesn't work
|
||||||
|
* reapply MQTT_MAX_PACKET_SIZE 256 and MQTT_KEEPALIVE 120 to PubSubClient.h
|
||||||
|
* Add status 0 option displaying all status messages
|
||||||
|
* Change MQTT_MAX_PACKET_SIZE from 1024 to 256
|
||||||
|
* Add buffer overflow checks (snprintf and strncpy)
|
||||||
|
* Implemented common string sizes
|
||||||
|
*
|
||||||
|
* 1.0.14 20160722
|
||||||
|
* Seperate user config from sonoff.ino to user_config.h (pucebaboon)
|
||||||
|
* Change defaults from sidnas2 to domus1
|
||||||
|
* Add MQTT status message as status 6 (pucebaboon)
|
||||||
|
* Add status type to message (pucebaboon)
|
||||||
|
* Add pubsubclient config changes to sonoff.ino (pucebaboon)
|
||||||
|
*
|
||||||
|
* 1.0.13 20160702
|
||||||
|
* Add Ledstate 1 option to show power state on led
|
||||||
|
*
|
||||||
|
* 1.0.12 20160529
|
||||||
|
* Allow disable of button topic using "0"
|
||||||
|
*
|
||||||
|
* 1.0.11 20160524
|
||||||
|
* Provide button response if MQTT connection lost
|
||||||
|
*
|
||||||
|
* 1.0.10 20160520
|
||||||
|
* Add optional button topic to assist external MQTT clients
|
||||||
|
* Change version notation
|
||||||
|
* Reset default values
|
||||||
|
*
|
||||||
|
* 1.0.9 20160503
|
||||||
|
* Add more blinks
|
||||||
|
* Add reset 2 option erasing flash
|
||||||
|
* Add status 5 option displaying network info
|
||||||
|
* Add syslog check for Wifi connection
|
||||||
|
* Resize mqtt_publish log array
|
||||||
|
* Change Wifi smartconfig active from 100 to 60 seconds
|
||||||
|
* Update Wifi initialization
|
||||||
|
*
|
||||||
|
* 1.0.8 20160430
|
||||||
|
* Remove use of Wifi config data from SDK
|
||||||
|
* Add status 3 (syslog info) and status 4 (flash info)
|
||||||
|
* Add restart option to button (5 quick presses)
|
||||||
|
*
|
||||||
|
* 1.0.7 20160420
|
||||||
|
* Add UDP syslog support
|
||||||
|
* Change HOST command to MQTTHOST command
|
||||||
|
* Add commands SYSLOG, SERIALLOG and LOGHOST
|
||||||
|
* Change hostname to lower case to distinguise between open-sdk version
|
||||||
|
* Add support for ESP-12F used in my modified wkaku power socket switch
|
||||||
|
* Fix timezone command
|
||||||
|
* Add RTC month names for future use
|
||||||
|
* Modify button code
|
||||||
|
* Remove initialization errors by better use of MQTT loop
|
||||||
|
*
|
||||||
|
* 1.0.6 20160406
|
||||||
|
* Removed Wifi AP mode (#1)
|
||||||
|
* Add test for Arduino IDE version >= 1.6.8
|
||||||
|
* Fix RTC time sync code
|
||||||
|
*
|
||||||
|
* 1.0.5 20160310
|
||||||
|
* Initial public release
|
||||||
|
* Show debug info by selecting option from IDE Tools Debug port: Serial
|
||||||
|
*/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,248 @@
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Template parameters
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define GPIO_SENSOR_START 0
|
||||||
|
#define GPIO_NONE 0 // Not used
|
||||||
|
#define GPIO_DHT11 1 // DHT11
|
||||||
|
#define GPIO_DHT21 2 // DHT21
|
||||||
|
#define GPIO_AM2301 2 // AM2301
|
||||||
|
#define GPIO_DHT22 3 // DHT22
|
||||||
|
#define GPIO_AM2302 3 // AM2302
|
||||||
|
#define GPIO_AM2321 3 // AM2321
|
||||||
|
#define GPIO_DSB 4 // Single wire DS18B20 or DS18S20
|
||||||
|
#define GPIO_I2C_SCL 5 // I2C SCL
|
||||||
|
#define GPIO_I2C_SDA 6 // I2C SDA
|
||||||
|
#define GPIO_WS2812 7 // WS2812 Led string
|
||||||
|
#define GPIO_SWT1 8 // User connected external switches
|
||||||
|
#define GPIO_SENSOR_END 9
|
||||||
|
|
||||||
|
#define GPIO_SWT2 9
|
||||||
|
#define GPIO_SWT3 10
|
||||||
|
#define GPIO_SWT4 11
|
||||||
|
#define GPIO_KEY1 12 // Button usually connected to GPIO0
|
||||||
|
#define GPIO_KEY2 13
|
||||||
|
#define GPIO_KEY3 14
|
||||||
|
#define GPIO_KEY4 15
|
||||||
|
#define GPIO_REL1 16 // Relays
|
||||||
|
#define GPIO_REL2 17
|
||||||
|
#define GPIO_REL3 18
|
||||||
|
#define GPIO_REL4 19
|
||||||
|
#define GPIO_REL1_INV 20
|
||||||
|
#define GPIO_REL2_INV 21
|
||||||
|
#define GPIO_REL3_INV 22
|
||||||
|
#define GPIO_REL4_INV 23
|
||||||
|
#define GPIO_LED1 24 // Leds
|
||||||
|
#define GPIO_LED2 25
|
||||||
|
#define GPIO_LED3 26
|
||||||
|
#define GPIO_LED4 27
|
||||||
|
#define GPIO_LED1_INV 28
|
||||||
|
#define GPIO_LED2_INV 29
|
||||||
|
#define GPIO_LED3_INV 30
|
||||||
|
#define GPIO_LED4_INV 31
|
||||||
|
#define GPIO_PWM0 32 // Cold
|
||||||
|
#define GPIO_PWM1 33 // Warm
|
||||||
|
#define GPIO_PWM2 34 // Red (swapped with Blue from original)
|
||||||
|
#define GPIO_PWM3 35 // Green
|
||||||
|
#define GPIO_PWM4 36 // Blue (swapped with Red from original)
|
||||||
|
#define GPIO_RXD 37 // Serial interface
|
||||||
|
#define GPIO_TXD 38 // Serial interface
|
||||||
|
#define GPIO_HLW_SEL 39 // HLW8012 Sel output (Sonoff Pow)
|
||||||
|
#define GPIO_HLW_CF1 40 // HLW8012 CF1 voltage / current (Sonoff Pow)
|
||||||
|
#define GPIO_HLW_CF 41 // HLW8012 CF power (Sonoff Pow)
|
||||||
|
#define GPIO_USER 42 // User configurable
|
||||||
|
#define GPIO_MAX 43
|
||||||
|
|
||||||
|
/********************************************************************************************/
|
||||||
|
|
||||||
|
enum module_t {SONOFF_BASIC, SONOFF_RF, SONOFF_SV, SONOFF_TH, SONOFF_DUAL, SONOFF_POW, SONOFF_4CH, S20, SLAMPHER, SONOFF_TOUCH, SONOFF_LED, CH1, CH4, MOTOR, ELECTRODRAGON, USER_TEST, MAXMODULE};
|
||||||
|
|
||||||
|
/********************************************************************************************/
|
||||||
|
|
||||||
|
#define MAX_GPIO_PIN 17 // Number of supported GPIO
|
||||||
|
|
||||||
|
#define DHT11 11
|
||||||
|
#define DHT21 21
|
||||||
|
#define AM2301 21
|
||||||
|
#define DHT22 22
|
||||||
|
#define AM2302 22
|
||||||
|
#define AM2321 22
|
||||||
|
|
||||||
|
typedef struct MYIO {
|
||||||
|
uint8_t io[MAX_GPIO_PIN];
|
||||||
|
} myio;
|
||||||
|
|
||||||
|
typedef struct MYTMPLT {
|
||||||
|
char name[16];
|
||||||
|
myio gp;
|
||||||
|
} mytmplt;
|
||||||
|
|
||||||
|
const char sensors[GPIO_SENSOR_END][8] PROGMEM =
|
||||||
|
{ "None", "DHT11", "AM2301", "DHT22", "DS18x20", "I2C SCL", "I2C SDA", "WS2812", "Switch" };
|
||||||
|
|
||||||
|
const mytmplt modules[MAXMODULE] PROGMEM = {
|
||||||
|
{ "Sonoff Basic", // Sonoff Basic
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0,
|
||||||
|
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
||||||
|
GPIO_USER, // GPIO04 Optional sensor
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
|
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||||
|
GPIO_USER, // GPIO14 Optional sensor
|
||||||
|
0, 0
|
||||||
|
},
|
||||||
|
{ "Sonoff RF", // Sonoff RF
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0,
|
||||||
|
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
||||||
|
GPIO_USER, // GPIO04 Optional sensor
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
|
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||||
|
GPIO_USER, // GPIO14 Optional sensor
|
||||||
|
0, 0
|
||||||
|
},
|
||||||
|
{ "Sonoff SV", // Sonoff SV
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0,
|
||||||
|
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
||||||
|
GPIO_USER, // GPIO04 Optional sensor
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
|
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||||
|
GPIO_USER, // GPIO14 Optional sensor
|
||||||
|
0, 0
|
||||||
|
},
|
||||||
|
{ "Sonoff TH", // Sonoff TH10/16
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0,
|
||||||
|
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
||||||
|
GPIO_USER, // GPIO04 Optional sensor
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
|
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||||
|
GPIO_USER, // GPIO14 Optional sensor
|
||||||
|
0, 0
|
||||||
|
},
|
||||||
|
{ "Sonoff Dual", // Sonoff Dual
|
||||||
|
0,
|
||||||
|
GPIO_TXD, // GPIO01 Relay control
|
||||||
|
0,
|
||||||
|
GPIO_RXD, // GPIO03 Relay control
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
|
||||||
|
0, 0, 0
|
||||||
|
},
|
||||||
|
{ "Sonoff Pow", // Sonoff Pow
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0, 0, 0,
|
||||||
|
GPIO_HLW_SEL, // GPIO05 HLW8012 Sel output
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
|
GPIO_HLW_CF1, // GPIO13 HLW8012 CF1 voltage / current
|
||||||
|
GPIO_HLW_CF, // GPIO14 HLW8012 CF power
|
||||||
|
GPIO_LED1, // GPIO15 Green Led (0 = On, 1 = Off)
|
||||||
|
0
|
||||||
|
},
|
||||||
|
{ "Sonoff 4CH", // Sonoff 4CH
|
||||||
|
GPIO_KEY1, // GPIO00 Button 1
|
||||||
|
0,
|
||||||
|
GPIO_USER, // GPIO02 Optional sensor
|
||||||
|
0,
|
||||||
|
GPIO_REL3, // GPIO04 Sonoff 4CH Red Led and Relay 3 (0 = Off, 1 = On)
|
||||||
|
GPIO_REL2, // GPIO05 Sonoff 4CH Red Led and Relay 2 (0 = Off, 1 = On)
|
||||||
|
0,
|
||||||
|
GPIO_USER, // GPIO07 Optional sensor
|
||||||
|
GPIO_USER, // GPIO08 Optional sensor
|
||||||
|
GPIO_KEY2, // GPIO09 Button 2
|
||||||
|
GPIO_KEY3, // GPIO10 Button 3
|
||||||
|
0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay 1 (0 = Off, 1 = On)
|
||||||
|
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||||
|
GPIO_KEY4, // GPIO14 Button 4
|
||||||
|
GPIO_REL4, // GPIO15 Red Led and Relay 4 (0 = Off, 1 = On)
|
||||||
|
0
|
||||||
|
},
|
||||||
|
{ "S20 Socket", // S20 Smart Socket
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
|
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||||
|
0, 0, 0
|
||||||
|
},
|
||||||
|
{ "Slampher", // Slampher
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
|
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
|
||||||
|
0, 0, 0
|
||||||
|
},
|
||||||
|
{ "Sonoff Touch", // Sonoff Touch
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
|
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
|
||||||
|
0, 0, 0
|
||||||
|
},
|
||||||
|
{ "Sonoff LED", // Sonoff LED
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0, 0,
|
||||||
|
GPIO_PWM3, // GPIO04 Green light
|
||||||
|
GPIO_PWM2, // GPIO05 Red light
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_PWM0, // GPIO12 Cold light
|
||||||
|
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
|
||||||
|
GPIO_PWM1, // GPIO14 Warm light
|
||||||
|
GPIO_PWM4, // GPIO15 Blue light
|
||||||
|
0
|
||||||
|
},
|
||||||
|
{ "1 Channel", // 1 Channel Inching/Latching Relay
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
|
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||||
|
0, 0, 0
|
||||||
|
},
|
||||||
|
{ "4 Channel", // 4 Channel Inching/Latching Relays
|
||||||
|
0,
|
||||||
|
GPIO_TXD, // GPIO01 Relay control
|
||||||
|
0,
|
||||||
|
GPIO_RXD, // GPIO03 Relay control
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
|
||||||
|
0, 0, 0
|
||||||
|
},
|
||||||
|
{ "Motor C/AC", // Motor Clockwise / Anti clockwise
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
|
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||||
|
0, 0, 0
|
||||||
|
},
|
||||||
|
{ "ElectroDragon", // ElectroDragon IoT Relay Board
|
||||||
|
GPIO_KEY2, // GPIO00 Button 2
|
||||||
|
0,
|
||||||
|
GPIO_KEY1, // GPIO02 Button 1
|
||||||
|
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
||||||
|
GPIO_USER, // GPIO04 Optional sensor
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL2, // GPIO12 Red Led and Relay 2 (0 = Off, 1 = On)
|
||||||
|
GPIO_REL1, // GPIO13 Red Led and Relay 1 (0 = Off, 1 = On)
|
||||||
|
GPIO_USER, // GPIO14 Optional sensor
|
||||||
|
0,
|
||||||
|
GPIO_LED1 // GPIO16 Green/Blue Led (1 = On, 0 = Off)
|
||||||
|
},
|
||||||
|
{ "User Test", // Sonoff Basic User Test
|
||||||
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
0, 0,
|
||||||
|
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
||||||
|
GPIO_USER, // GPIO04 Optional sensor
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
|
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||||
|
GPIO_USER, // GPIO14 Optional sensor
|
||||||
|
0, 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __SUPPORT_H__
|
||||||
|
#define __SUPPORT_H__
|
||||||
|
|
||||||
|
#include "user_interface.h"
|
||||||
|
|
||||||
|
/* Function prototypes. */
|
||||||
|
void WIFI_wps_status_cb(wps_cb_status status);
|
||||||
|
|
||||||
|
#endif // ifndef __SUPPORT_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,147 @@
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* User specific configuration parameters
|
||||||
|
*
|
||||||
|
* ATTENTION: Changes to most PARAMETER defines will only override flash settings if you change
|
||||||
|
* define CFG_HOLDER.
|
||||||
|
* Most parameters can be changed online using commands via MQTT, WebConsole or serial
|
||||||
|
*
|
||||||
|
* Corresponding MQTT/Serial/Console commands in [brackets]
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
// -- Project -------------------------------------
|
||||||
|
#define PROJECT "sonoff" // PROJECT is used as the default topic delimiter and OTA file name
|
||||||
|
// As an IDE restriction it needs to be the same as the main .ino file
|
||||||
|
|
||||||
|
#define CFG_HOLDER 0x20161209 // [Reset 1] Change this value to load following default configuration parameters
|
||||||
|
#define SAVE_DATA 1 // [SaveData] Save changed parameters to Flash (0 = disable, 1 - 3600 seconds)
|
||||||
|
#define SAVE_STATE 1 // [SaveState] Save changed power state to Flash (0 = disable, 1 = enable)
|
||||||
|
|
||||||
|
// -- Wifi ----------------------------------------
|
||||||
|
#define STA_SSID1 "indebuurt1" // [Ssid1] Wifi SSID
|
||||||
|
#define STA_PASS1 "VnsqrtnrsddbrN" // [Password1] Wifi password
|
||||||
|
#define STA_SSID2 "indebuurt2" // [Ssid2] Optional alternate AP Wifi SSID
|
||||||
|
#define STA_PASS2 "VnsqrtnrsddbrN" // [Password2] Optional alternate AP Wifi password
|
||||||
|
#define WIFI_HOSTNAME "%s-%04d" // [Hostname] Expands to <MQTT_TOPIC>-<last 4 decimal chars of MAC address>
|
||||||
|
#define WIFI_CONFIG_TOOL WIFI_WPSCONFIG // [WifiConfig] Default tool if wifi fails to connect
|
||||||
|
// (WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY)
|
||||||
|
// -- Syslog --------------------------------------
|
||||||
|
#define SYS_LOG_HOST "domus1" // [LogHost] (Linux) syslog host
|
||||||
|
#define SYS_LOG_PORT 514 // [LogPort] default syslog UDP port
|
||||||
|
#define SYS_LOG_LEVEL LOG_LEVEL_NONE // [SysLog]
|
||||||
|
#define SERIAL_LOG_LEVEL LOG_LEVEL_INFO // [SerialLog]
|
||||||
|
#define WEB_LOG_LEVEL LOG_LEVEL_INFO // [WebLog]
|
||||||
|
|
||||||
|
// -- Ota -----------------------------------------
|
||||||
|
#define OTA_URL "http://domus1:80/api/arduino/" PROJECT ".ino.bin" // [OtaUrl]
|
||||||
|
|
||||||
|
// -- MQTT ----------------------------------------
|
||||||
|
#define MQTT_USE 1 // [Mqtt] Select default MQTT use (0 = Off, 1 = On)
|
||||||
|
// !!! TLS uses a LOT OF MEMORY (20k) so be careful to enable other options at the same time !!!
|
||||||
|
//#define USE_MQTT_TLS // EXPERIMENTAL Use TLS for MQTT connection (+53k code, +20k mem)
|
||||||
|
// Needs Fingerprint, TLS Port, UserId and Password
|
||||||
|
#ifdef USE_MQTT_TLS
|
||||||
|
#define MQTT_HOST "m20.cloudmqtt.com" // [MqttHost]
|
||||||
|
#define MQTT_FINGERPRINT "A5 02 FF 13 99 9F 8B 39 8E F1 83 4F 11 23 65 0B 32 36 FC 07" // [MqttFingerprint]
|
||||||
|
#define MQTT_PORT 20123 // [MqttPort] MQTT TLS port
|
||||||
|
#define MQTT_USER "cloudmqttuser" // [MqttUser] Mandatory user
|
||||||
|
#define MQTT_PASS "cloudmqttpassword" // [MqttPassword] Mandatory password
|
||||||
|
#else
|
||||||
|
#define MQTT_HOST "domus1" // [MqttHost]
|
||||||
|
#define MQTT_PORT 1883 // [MqttPort] MQTT port (10123 on CloudMQTT)
|
||||||
|
#define MQTT_USER "DVES_USER" // [MqttUser] Optional user
|
||||||
|
#define MQTT_PASS "DVES_PASS" // [MqttPassword] Optional password
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MQTT_CLIENT_ID "DVES_%06X" // [MqttClient] Also fall back topic using Chip Id = last 6 characters of MAC address
|
||||||
|
|
||||||
|
#define SUB_PREFIX "cmnd" // Sonoff devices subscribe to:- SUB_PREFIX/MQTT_TOPIC and SUB_PREFIX/MQTT_GRPTOPIC
|
||||||
|
#define PUB_PREFIX "stat" // Sonoff devices publish to:- PUB_PREFIX/MQTT_TOPIC
|
||||||
|
#define PUB_PREFIX2 "tele" // Sonoff devices publish telemetry data to:- PUB_PREFIX2/MQTT_TOPIC/UPTIME, POWER/LIGHT and TIME
|
||||||
|
// May be named the same as PUB_PREFIX
|
||||||
|
#define MQTT_TOPIC PROJECT // [Topic] (unique) MQTT device topic
|
||||||
|
#define MQTT_GRPTOPIC "sonoffs" // [GroupTopic] MQTT Group topic
|
||||||
|
#define MQTT_BUTTON_RETAIN 0 // [ButtonRetain] Button may send retain flag (0 = off, 1 = on)
|
||||||
|
#define MQTT_POWER_RETAIN 0 // [PowerRetain] Power status message may send retain flag (0 = off, 1 = on)
|
||||||
|
#define MQTT_SWITCH_RETAIN 0 // [SwitchRetain] Switch may send retain flag (0 = off, 1 = on)
|
||||||
|
|
||||||
|
#define MQTT_STATUS_OFF "OFF" // Command or Status result when turned off (needs to be a string like "0" or "Off")
|
||||||
|
#define MQTT_STATUS_ON "ON" // Command or Status result when turned on (needs to be a string like "1" or "On")
|
||||||
|
#define MQTT_CMND_TOGGLE "TOGGLE" // Command to send when toggling (needs to be a string like "2" or "Toggle")
|
||||||
|
|
||||||
|
// -- MQTT - Telemetry ----------------------------
|
||||||
|
#define TELE_PERIOD 300 // [TelePeriod] Telemetry (0 = disable, 10 - 3600 seconds)
|
||||||
|
|
||||||
|
// -- MQTT - Domoticz -----------------------------
|
||||||
|
#define USE_DOMOTICZ // Enable Domoticz (+5k code, +0.3k mem) - Disable by //
|
||||||
|
#define DOMOTICZ_IN_TOPIC "domoticz/in" // [DomoticzInTopic]
|
||||||
|
#define DOMOTICZ_OUT_TOPIC "domoticz/out" // [DomoticzOutTopic]
|
||||||
|
#define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) (Optional)
|
||||||
|
|
||||||
|
// -- HTTP ----------------------------------------
|
||||||
|
#define USE_WEBSERVER // Enable web server and wifi manager (+43k code, +2k mem) - Disable by //
|
||||||
|
#define FRIENDLY_NAME1 "Sonoff" // [FriendlyName1] Friendlyname up to 32 characters used by webpages and Alexa
|
||||||
|
#define FRIENDLY_NAME2 "Sonoff2" // [FriendlyName2] Friendlyname up to 32 characters used by Alexa
|
||||||
|
#define FRIENDLY_NAME3 "Sonoff3" // [FriendlyName3] Friendlyname up to 32 characters used by Alexa
|
||||||
|
#define FRIENDLY_NAME4 "Sonoff4" // [FriendlyName4] Friendlyname up to 32 characters used by Alexa
|
||||||
|
#define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin)
|
||||||
|
// #define USE_WEMO_EMULATION // Enable Belkin WeMo PowerSwitch emulation for Alexa (+4k code, +2k mem)
|
||||||
|
// #define USE_HUE_EMULATION // Enable Hue Bridge emulation for Alexa (+5k code, +2k mem)
|
||||||
|
|
||||||
|
// -- mDNS ----------------------------------------
|
||||||
|
#define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem)
|
||||||
|
#define WEBSERVER_ADVERTISE // Provide access to webserver by name <Hostname>.local/
|
||||||
|
#define MQTT_HOST_DISCOVERY // Find MQTT host server (overrides MQTT_HOST if found)
|
||||||
|
|
||||||
|
// -- Time - Up to three NTP servers in your region
|
||||||
|
#define NTP_SERVER1 "pool.ntp.org"
|
||||||
|
#define NTP_SERVER2 "nl.pool.ntp.org"
|
||||||
|
#define NTP_SERVER3 "0.nl.pool.ntp.org"
|
||||||
|
|
||||||
|
// -- Time - Start Daylight Saving Time and timezone offset from UTC in minutes
|
||||||
|
#define TIME_DST Last, Sun, Mar, 2, +120 // Last sunday in march at 02:00 +120 minutes
|
||||||
|
|
||||||
|
// -- Time - Start Standard Time and timezone offset from UTC in minutes
|
||||||
|
#define TIME_STD Last, Sun, Oct, 3, +60 // Last sunday in october 02:00 +60 minutes
|
||||||
|
|
||||||
|
// -- Application ---------------------------------
|
||||||
|
#define APP_TIMEZONE 1 // [Timezone] +1 hour (Amsterdam) (-12 .. 12 = hours from UTC, 99 = use TIME_DST/TIME_STD)
|
||||||
|
#define APP_LEDSTATE LED_POWER // [LedState] Function of led (LED_OFF, LED_POWER, LED_MQTTSUB, LED_POWER_MQTTSUB, LED_MQTTPUB, LED_POWER_MQTTPUB, LED_MQTT, LED_POWER_MQTT)
|
||||||
|
#define APP_PULSETIME 0 // [PulseTime] Time in 0.1 Sec to turn off power for relay 1 (0 = disabled)
|
||||||
|
#define APP_POWERON_STATE 3 // [PowerOnState] Power On Relay state (0 = Off, 1 = On, 2 = Toggle Saved state, 3 = Saved state)
|
||||||
|
#define APP_BLINKTIME 10 // [BlinkTime] Time in 0.1 Sec to blink/toggle power for relay 1
|
||||||
|
#define APP_BLINKCOUNT 10 // [BlinkCount] Number of blinks (0 = 32000)
|
||||||
|
#define APP_SLEEP 0 // [Sleep] Sleep time to lower energy consumption (0 = Off, 1 - 250 mSec)
|
||||||
|
|
||||||
|
#define SWITCH_MODE TOGGLE // [SwitchMode] TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON or PUSHBUTTON_INV (the wall switch state)
|
||||||
|
#define WS2812_LEDS 30 // [Pixels] Number of WS2812 LEDs to start with
|
||||||
|
|
||||||
|
#define TEMP_CONVERSION 0 // Convert temperature to (0 = Celsius or 1 = Fahrenheit)
|
||||||
|
#define TEMP_RESOLUTION 1 // Maximum number of decimals (0 - 3) showing sensor Temperature
|
||||||
|
#define HUMIDITY_RESOLUTION 1 // Maximum number of decimals (0 - 3) showing sensor Humidity
|
||||||
|
#define PRESSURE_RESOLUTION 1 // Maximum number of decimals (0 - 3) showing sensor Pressure
|
||||||
|
|
||||||
|
// -- Sensor code selection -----------------------
|
||||||
|
//#define USE_DHT2 // Optional using Adafruit DHT library
|
||||||
|
//#define USE_DS18x20 // Optional using OneWire library for multiple DS18B20 and/or DS18S20
|
||||||
|
|
||||||
|
#define USE_I2C // I2C Support (+10k code, 0.2k mem)
|
||||||
|
#define USE_BH1750 // Add I2C code for BH1750 sensor
|
||||||
|
#define USE_BMP // Add I2C code for BMP/BME280 sensor
|
||||||
|
#define USE_HTU // Add I2C code for HTU21 sensor
|
||||||
|
|
||||||
|
#define USE_WS2812 // WS2812 Led string support (+8k code, +1k mem)
|
||||||
|
// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial TXD) (+1k mem)
|
||||||
|
// When USE_WS2812_DMA is enabled expect Exceptions on Pow
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* No user configurable items below
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#if defined(USE_WEMO_EMULATION) && defined(USE_HUE_EMULATION)
|
||||||
|
#error "Select either USE_WEMO_EMULATION or USE_HUE_EMULATION"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (ARDUINO < 10610)
|
||||||
|
#error "This software is supported with Arduino IDE starting from 1.6.10 and ESP8266 Release 2.3.0"
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*****************************************************************************************************\
|
||||||
|
* User specific configuration parameters to override user_config.h
|
||||||
|
*
|
||||||
|
* ATTENTION: - Changes to most PARAMETER defines will only override flash settings if you change
|
||||||
|
* define CFG_HOLDER.
|
||||||
|
* - Expect compiler warnings when no ifdef/undef/endif sequence is used.
|
||||||
|
* - You still need to update user_config.h for major defines MODULE and USE_MQTT_TLS.
|
||||||
|
* - Changing MODULE defines are not being tested for validity as they are in user_config.h.
|
||||||
|
* - Most parameters can be changed online using commands via MQTT, WebConsole or serial.
|
||||||
|
* - So I see no use in this but anyway, your on your own.
|
||||||
|
\*****************************************************************************************************/
|
||||||
|
|
||||||
|
// Examples
|
||||||
|
//#ifdef CFG_HOLDER
|
||||||
|
//#undef CFG_HOLDER
|
||||||
|
//#endif
|
||||||
|
//#define CFG_HOLDER 0x20161210
|
||||||
|
|
||||||
|
//#ifdef STA_SSID1
|
||||||
|
//#undef STA_SSID1
|
||||||
|
//#endif
|
||||||
|
//#define STA_SSID1 "yourssid1"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,376 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Theo Arends. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_DOMOTICZ
|
||||||
|
|
||||||
|
#define DOMOTICZ_MAX_SENSORS 5
|
||||||
|
|
||||||
|
const char HTTP_FORM_DOMOTICZ[] PROGMEM =
|
||||||
|
"<fieldset><legend><b> Domoticz parameters </b></legend><form method='post' action='sv'>"
|
||||||
|
"<input id='w' name='w' value='4' hidden><input id='r' name='r' value='1' hidden>"
|
||||||
|
"<br/><table style='width:97%'>"
|
||||||
|
"<tr><td><b>In topic</b> (" DOMOTICZ_IN_TOPIC ")</td><td style='width:30%'><input id='it' name='it' length=32 placeholder='" DOMOTICZ_IN_TOPIC "' value='{d1}'></td></tr>"
|
||||||
|
"<tr><td><b>Out topic</b> (" DOMOTICZ_OUT_TOPIC ")</td><td><input id='ot' name='ot' length=32 placeholder='" DOMOTICZ_OUT_TOPIC "' value='{d2}'></td></tr>";
|
||||||
|
|
||||||
|
const char domoticz_sensors[DOMOTICZ_MAX_SENSORS][14] PROGMEM =
|
||||||
|
{ "Temp", "Temp,Hum", "Temp,Hum,Baro", "Power,Energy", "Illuminance" };
|
||||||
|
|
||||||
|
int domoticz_update_timer = 0;
|
||||||
|
byte domoticz_update_flag = 1;
|
||||||
|
|
||||||
|
unsigned long getKeyIntValue(const char *json, const char *key)
|
||||||
|
{
|
||||||
|
char *p, *b, log[LOGSZ];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// search key
|
||||||
|
p = strstr(json, key);
|
||||||
|
if (!p) return 0;
|
||||||
|
// search following separator :
|
||||||
|
b = strchr(p + strlen(key), ':');
|
||||||
|
if (!b) return 0;
|
||||||
|
// Only the following chars are allowed between key and separator :
|
||||||
|
for(i = b - json + strlen(key); i < p-json; i++) {
|
||||||
|
switch (json[i]) {
|
||||||
|
case ' ':
|
||||||
|
case '\n':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b++;
|
||||||
|
// Allow integers as string too (used in "svalue" : "9")
|
||||||
|
while ((b[0] == ' ') || (b[0] == '"')) b++;
|
||||||
|
// Convert to integer
|
||||||
|
return atoi(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mqtt_publishDomoticzPowerState(byte device)
|
||||||
|
{
|
||||||
|
char svalue[MESSZ];
|
||||||
|
|
||||||
|
if (sysCfg.domoticz_relay_idx[device -1] && (strlen(sysCfg.domoticz_in_topic) != 0)) {
|
||||||
|
if ((device < 1) || (device > Maxdevice)) device = 1;
|
||||||
|
|
||||||
|
if (sysCfg.module == SONOFF_LED) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("{\"idx\":%d,\"nvalue\":2,\"svalue\":\"%d\"}"),
|
||||||
|
sysCfg.domoticz_relay_idx[device -1], sysCfg.led_dimmer[device -1]);
|
||||||
|
mqtt_publish(sysCfg.domoticz_in_topic, svalue);
|
||||||
|
}
|
||||||
|
else if ((device == 1) && (pin[GPIO_WS2812] < 99)) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("{\"idx\":%d,\"nvalue\":2,\"svalue\":\"%d\"}"),
|
||||||
|
sysCfg.domoticz_relay_idx[device -1], sysCfg.ws_dimmer);
|
||||||
|
mqtt_publish(sysCfg.domoticz_in_topic, svalue);
|
||||||
|
}
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("{\"idx\":%d,\"nvalue\":%d,\"svalue\":\"\"}"),
|
||||||
|
sysCfg.domoticz_relay_idx[device -1], (power & (0x01 << (device -1))) ? 1 : 0);
|
||||||
|
mqtt_publish(sysCfg.domoticz_in_topic, svalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void domoticz_updatePowerState(byte device)
|
||||||
|
{
|
||||||
|
if (domoticz_update_flag) mqtt_publishDomoticzPowerState(device);
|
||||||
|
domoticz_update_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void domoticz_mqttUpdate()
|
||||||
|
{
|
||||||
|
if ((sysCfg.domoticz_update_timer || domoticz_update_timer) && sysCfg.domoticz_relay_idx[0]) {
|
||||||
|
domoticz_update_timer--;
|
||||||
|
if (domoticz_update_timer <= 0) {
|
||||||
|
domoticz_update_timer = sysCfg.domoticz_update_timer;
|
||||||
|
for (byte i = 1; i <= Maxdevice; i++) mqtt_publishDomoticzPowerState(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void domoticz_setUpdateTimer(uint16_t value)
|
||||||
|
{
|
||||||
|
domoticz_update_timer = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void domoticz_mqttSubscribe()
|
||||||
|
{
|
||||||
|
if (sysCfg.domoticz_relay_idx[0] && (strlen(sysCfg.domoticz_out_topic) != 0)) {
|
||||||
|
char stopic[TOPSZ];
|
||||||
|
snprintf_P(stopic, sizeof(stopic), PSTR("%s/#"), sysCfg.domoticz_out_topic); // domoticz topic
|
||||||
|
mqttClient.subscribe(stopic);
|
||||||
|
mqttClient.loop(); // Solve LmacRxBlk:1 messages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean domoticz_update()
|
||||||
|
{
|
||||||
|
return domoticz_update_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean domoticz_mqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t sdataBuf)
|
||||||
|
{
|
||||||
|
char log[LOGSZ], stemp1[10];
|
||||||
|
unsigned long idx = 0;
|
||||||
|
int16_t nvalue, found = 0;
|
||||||
|
|
||||||
|
domoticz_update_flag = 1;
|
||||||
|
if (!strncmp(topicBuf, sysCfg.domoticz_out_topic, strlen(sysCfg.domoticz_out_topic)) != 0) {
|
||||||
|
if (sdataBuf < 20) return 1;
|
||||||
|
idx = getKeyIntValue(dataBuf,"\"idx\"");
|
||||||
|
nvalue = getKeyIntValue(dataBuf,"\"nvalue\"");
|
||||||
|
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("DMTZ: idx %d, nvalue %d"), idx, nvalue);
|
||||||
|
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||||
|
|
||||||
|
if (nvalue >= 0 && nvalue <= 2) {
|
||||||
|
for (byte i = 0; i < Maxdevice; i++) {
|
||||||
|
if ((idx > 0) && (idx == sysCfg.domoticz_relay_idx[i])) {
|
||||||
|
snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), i +1);
|
||||||
|
if (nvalue == 2) {
|
||||||
|
nvalue = getKeyIntValue(dataBuf,"\"svalue1\"");
|
||||||
|
if ((pin[GPIO_WS2812] < 99) && (sysCfg.ws_dimmer == nvalue)) return 1;
|
||||||
|
if ((sysCfg.module == SONOFF_LED) && (sysCfg.led_dimmer[i] == nvalue)) return 1;
|
||||||
|
snprintf_P(topicBuf, stopicBuf, PSTR("%s/%s/DIMMER%s"),
|
||||||
|
SUB_PREFIX, sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp1 : "");
|
||||||
|
snprintf_P(dataBuf, sdataBuf, PSTR("%d"), nvalue);
|
||||||
|
found = 1;
|
||||||
|
} else {
|
||||||
|
if (((power >> i) &1) == nvalue) return 1;
|
||||||
|
snprintf_P(topicBuf, stopicBuf, PSTR("%s/%s/%s%s"),
|
||||||
|
SUB_PREFIX, sysCfg.mqtt_topic, sysCfg.mqtt_subtopic, (Maxdevice > 1) ? stemp1 : "");
|
||||||
|
snprintf_P(dataBuf, sdataBuf, PSTR("%d"), nvalue);
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) return 1;
|
||||||
|
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("DMTZ: Receive topic %s, data %s"), topicBuf, dataBuf);
|
||||||
|
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||||
|
|
||||||
|
domoticz_update_flag = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Commands
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
void domoticz_commands(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue)
|
||||||
|
{
|
||||||
|
if (!strcmp(type,"DOMOTICZINTOPIC")) {
|
||||||
|
if ((data_len > 0) && (data_len < sizeof(sysCfg.domoticz_in_topic))) {
|
||||||
|
strlcpy(sysCfg.domoticz_in_topic, (payload == 1) ? DOMOTICZ_IN_TOPIC : dataBuf, sizeof(sysCfg.domoticz_in_topic));
|
||||||
|
restartflag = 2;
|
||||||
|
}
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzInTopic\":\"%s\"}"), sysCfg.domoticz_in_topic);
|
||||||
|
}
|
||||||
|
else if (!strcmp(type,"DOMOTICZOUTTOPIC")) {
|
||||||
|
if ((data_len > 0) && (data_len < sizeof(sysCfg.domoticz_out_topic))) {
|
||||||
|
strlcpy(sysCfg.domoticz_out_topic, (payload == 1) ? DOMOTICZ_OUT_TOPIC : dataBuf, sizeof(sysCfg.domoticz_out_topic));
|
||||||
|
restartflag = 2;
|
||||||
|
}
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzOutTopic\":\"%s\"}"), sysCfg.domoticz_out_topic);
|
||||||
|
}
|
||||||
|
else if (!strcmp(type,"DOMOTICZIDX") && (index > 0) && (index <= Maxdevice)) {
|
||||||
|
if ((data_len > 0) && (payload >= 0)) {
|
||||||
|
sysCfg.domoticz_relay_idx[index -1] = payload;
|
||||||
|
restartflag = 2;
|
||||||
|
}
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzIdx%d\":%d}"), index, sysCfg.domoticz_relay_idx[index -1]);
|
||||||
|
}
|
||||||
|
else if (!strcmp(type,"DOMOTICZKEYIDX") && (index > 0) && (index <= Maxdevice)) {
|
||||||
|
if ((data_len > 0) && (payload >= 0)) {
|
||||||
|
sysCfg.domoticz_key_idx[index -1] = payload;
|
||||||
|
}
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzKeyIdx%d\":%d}"), index, sysCfg.domoticz_key_idx[index -1]);
|
||||||
|
}
|
||||||
|
else if (!strcmp(type,"DOMOTICZSWITCHIDX") && (index > 0) && (index <= Maxdevice)) {
|
||||||
|
if ((data_len > 0) && (payload >= 0)) {
|
||||||
|
sysCfg.domoticz_switch_idx[index -1] = payload;
|
||||||
|
}
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzSwitchIdx%d\":%d}"), index, sysCfg.domoticz_key_idx[index -1]);
|
||||||
|
}
|
||||||
|
else if (!strcmp(type,"DOMOTICZSENSORIDX") && (index > 0) && (index <= DOMOTICZ_MAX_SENSORS)) {
|
||||||
|
if ((data_len > 0) && (payload >= 0)) {
|
||||||
|
sysCfg.domoticz_sensor_idx[index -1] = payload;
|
||||||
|
}
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzSensorIdx%d\":%d}"), index, sysCfg.domoticz_sensor_idx[index -1]);
|
||||||
|
}
|
||||||
|
else if (!strcmp(type,"DOMOTICZUPDATETIMER")) {
|
||||||
|
if ((data_len > 0) && (payload >= 0) && (payload < 3601)) {
|
||||||
|
sysCfg.domoticz_update_timer = payload;
|
||||||
|
}
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzUpdateTimer\":%d}"), sysCfg.domoticz_update_timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean domoticz_button(byte key, byte device, byte state, byte svalflg)
|
||||||
|
{
|
||||||
|
if ((sysCfg.domoticz_key_idx[device -1] || sysCfg.domoticz_switch_idx[device -1]) && (svalflg)) {
|
||||||
|
char svalue[MESSZ];
|
||||||
|
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("{\"command\":\"switchlight\",\"idx\":%d,\"switchcmd\":\"%s\"}"),
|
||||||
|
(key) ? sysCfg.domoticz_switch_idx[device -1] : sysCfg.domoticz_key_idx[device -1], (state) ? (state == 2) ? "Toggle" : "On" : "Off");
|
||||||
|
mqtt_publish(sysCfg.domoticz_in_topic, svalue);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Sensors
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
uint8_t dom_hum_stat(char *hum)
|
||||||
|
{
|
||||||
|
uint8_t h = atoi(hum);
|
||||||
|
return (!h) ? 0 : (h < 40) ? 2 : (h > 70) ? 3 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dom_sensor(byte idx, char *data)
|
||||||
|
{
|
||||||
|
char dmess[64];
|
||||||
|
|
||||||
|
if (sysCfg.domoticz_sensor_idx[idx] && (strlen(sysCfg.domoticz_in_topic) != 0)) {
|
||||||
|
snprintf_P(dmess, sizeof(dmess), PSTR("{\"idx\":%d,\"nvalue\":0,\"svalue\":\"%s\"}"),
|
||||||
|
sysCfg.domoticz_sensor_idx[idx], data);
|
||||||
|
mqtt_publish(sysCfg.domoticz_in_topic, dmess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void domoticz_sensor1(char *temp)
|
||||||
|
{
|
||||||
|
dom_sensor(0, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void domoticz_sensor2(char *temp, char *hum)
|
||||||
|
{
|
||||||
|
char data[16];
|
||||||
|
snprintf_P(data, sizeof(data), PSTR("%s;%s;%d"), temp, hum, dom_hum_stat(hum));
|
||||||
|
dom_sensor(1, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void domoticz_sensor3(char *temp, char *hum, char *baro)
|
||||||
|
{
|
||||||
|
char data[32];
|
||||||
|
snprintf_P(data, sizeof(data), PSTR("%s;%s;%d;%s;5"), temp, hum, dom_hum_stat(hum), baro);
|
||||||
|
dom_sensor(2, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void domoticz_sensor4(uint16_t power, char *energy)
|
||||||
|
{
|
||||||
|
char data[16];
|
||||||
|
snprintf_P(data, sizeof(data), PSTR("%d;%s"), power, energy);
|
||||||
|
dom_sensor(3, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void domoticz_sensor5(uint16_t lux)
|
||||||
|
{
|
||||||
|
char data[8];
|
||||||
|
snprintf_P(data, sizeof(data), PSTR("%d"), lux);
|
||||||
|
dom_sensor(4, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Presentation
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
void handleDomoticz()
|
||||||
|
{
|
||||||
|
if (_httpflag == HTTP_USER) {
|
||||||
|
handleRoot();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle Domoticz config"));
|
||||||
|
|
||||||
|
char stemp[20];
|
||||||
|
|
||||||
|
String page = FPSTR(HTTP_HEAD);
|
||||||
|
page.replace("{v}", "Configure Domoticz");
|
||||||
|
page += FPSTR(HTTP_FORM_DOMOTICZ);
|
||||||
|
page.replace("{d1}", String(sysCfg.domoticz_in_topic));
|
||||||
|
page.replace("{d2}", String(sysCfg.domoticz_out_topic));
|
||||||
|
for (int i = 0; i < Maxdevice; i++) {
|
||||||
|
page += F("<tr><td><b>Idx {1</b></td></td><td><input id='r{1' name='r{1' length=8 placeholder='0' value='{2'></td></tr>");
|
||||||
|
page += F("<tr><td><b>Key idx {1</b></td><td><input id='k{1' name='k{1' length=8 placeholder='0' value='{3'></td></tr>");
|
||||||
|
page += F("<tr><td><b>Switch idx {1</b></td><td><input id='s{1' name='s{1' length=8 placeholder='0' value='{4'></td></tr>");
|
||||||
|
page.replace("{1", String(i +1));
|
||||||
|
page.replace("{2", String((int)sysCfg.domoticz_relay_idx[i]));
|
||||||
|
page.replace("{3", String((int)sysCfg.domoticz_key_idx[i]));
|
||||||
|
page.replace("{4", String((int)sysCfg.domoticz_switch_idx[i]));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < DOMOTICZ_MAX_SENSORS; i++) {
|
||||||
|
page += F("<tr><td><b>Sensor idx {1</b> - {2</td><td><input id='l{1' name='l{1' length=8 placeholder='0' value='{4'></td></tr>");
|
||||||
|
page.replace("{1", String(i +1));
|
||||||
|
snprintf_P(stemp, sizeof(stemp), domoticz_sensors[i]);
|
||||||
|
page.replace("{2", stemp);
|
||||||
|
page.replace("{4", String((int)sysCfg.domoticz_sensor_idx[i]));
|
||||||
|
}
|
||||||
|
page += F("<tr><td><b>Update timer</b> (" STR(DOMOTICZ_UPDATE_TIMER) ")</td><td><input id='ut' name='ut' length=32 placeholder='" STR(DOMOTICZ_UPDATE_TIMER) "' value='{d7}'</td></tr>");
|
||||||
|
page.replace("{d7}", String((int)sysCfg.domoticz_update_timer));
|
||||||
|
page += F("</table>");
|
||||||
|
page += FPSTR(HTTP_FORM_END);
|
||||||
|
page += FPSTR(HTTP_BTN_CONF);
|
||||||
|
showPage(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
void domoticz_saveSettings()
|
||||||
|
{
|
||||||
|
char log[LOGSZ], stemp[20];
|
||||||
|
|
||||||
|
strlcpy(sysCfg.domoticz_in_topic, (!strlen(webServer->arg("it").c_str())) ? DOMOTICZ_IN_TOPIC : webServer->arg("it").c_str(), sizeof(sysCfg.domoticz_in_topic));
|
||||||
|
strlcpy(sysCfg.domoticz_out_topic, (!strlen(webServer->arg("ot").c_str())) ? DOMOTICZ_OUT_TOPIC : webServer->arg("ot").c_str(), sizeof(sysCfg.domoticz_out_topic));
|
||||||
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
snprintf_P(stemp, sizeof(stemp), PSTR("r%d"), i +1);
|
||||||
|
sysCfg.domoticz_relay_idx[i] = (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str());
|
||||||
|
snprintf_P(stemp, sizeof(stemp), PSTR("k%d"), i +1);
|
||||||
|
sysCfg.domoticz_key_idx[i] = (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str());
|
||||||
|
snprintf_P(stemp, sizeof(stemp), PSTR("s%d"), i +1);
|
||||||
|
sysCfg.domoticz_switch_idx[i] = (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str());
|
||||||
|
}
|
||||||
|
for (byte i = 0; i < DOMOTICZ_MAX_SENSORS; i++) {
|
||||||
|
snprintf_P(stemp, sizeof(stemp), PSTR("l%d"), i +1);
|
||||||
|
sysCfg.domoticz_sensor_idx[i] = (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str());
|
||||||
|
}
|
||||||
|
sysCfg.domoticz_update_timer = (!strlen(webServer->arg("ut").c_str())) ? DOMOTICZ_UPDATE_TIMER : atoi(webServer->arg("ut").c_str());
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("HTTP: Domoticz in %s, out %s, idx %d, %d, %d, %d, update timer %d"),
|
||||||
|
sysCfg.domoticz_in_topic, sysCfg.domoticz_out_topic,
|
||||||
|
sysCfg.domoticz_relay_idx[0], sysCfg.domoticz_relay_idx[1], sysCfg.domoticz_relay_idx[2], sysCfg.domoticz_relay_idx[3],
|
||||||
|
sysCfg.domoticz_update_timer);
|
||||||
|
addLog(LOG_LEVEL_INFO, log);
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("HTTP: key %d, %d, %d, %d, switch %d, %d, %d, %d, sensor %d, %d, %d, %d, %d"),
|
||||||
|
sysCfg.domoticz_key_idx[0], sysCfg.domoticz_key_idx[1], sysCfg.domoticz_key_idx[2], sysCfg.domoticz_key_idx[3],
|
||||||
|
sysCfg.domoticz_switch_idx[0], sysCfg.domoticz_switch_idx[1], sysCfg.domoticz_switch_idx[2], sysCfg.domoticz_switch_idx[3],
|
||||||
|
sysCfg.domoticz_sensor_idx[0], sysCfg.domoticz_sensor_idx[1], sysCfg.domoticz_sensor_idx[2], sysCfg.domoticz_sensor_idx[3], sysCfg.domoticz_sensor_idx[4]);
|
||||||
|
addLog(LOG_LEVEL_INFO, log);
|
||||||
|
}
|
||||||
|
#endif // USE_DOMOTICZ
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Heiko Krupp and Theo Arends. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(USE_WEMO_EMULATION) || defined(USE_HUE_EMULATION)
|
||||||
|
|
||||||
|
#define UDP_BUFFER_SIZE 200 // Max UDP buffer size needed for M-SEARCH message
|
||||||
|
|
||||||
|
boolean udpConnected = false;
|
||||||
|
|
||||||
|
char packetBuffer[UDP_BUFFER_SIZE]; // buffer to hold incoming UDP packet
|
||||||
|
IPAddress ipMulticast(239, 255, 255, 250); // Simple Service Discovery Protocol (SSDP)
|
||||||
|
uint32_t portMulticast = 1900; // Multicast address and port
|
||||||
|
|
||||||
|
#ifdef USE_WEMO_EMULATION
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* WeMo UPNP support routines
|
||||||
|
\*********************************************************************************************/
|
||||||
|
const char WEMO_MSEARCH[] PROGMEM =
|
||||||
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
"CACHE-CONTROL: max-age=86400\r\n"
|
||||||
|
"DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n"
|
||||||
|
"EXT:\r\n"
|
||||||
|
"LOCATION: http://{r1}:80/setup.xml\r\n"
|
||||||
|
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||||
|
"01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n"
|
||||||
|
"SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"
|
||||||
|
"ST: urn:Belkin:device:**\r\n"
|
||||||
|
"USN: uuid:{r2}::urn:Belkin:device:**\r\n"
|
||||||
|
"X-User-Agent: redsonic\r\n"
|
||||||
|
"\r\n";
|
||||||
|
|
||||||
|
String wemo_serial()
|
||||||
|
{
|
||||||
|
char serial[15];
|
||||||
|
snprintf_P(serial, sizeof(serial), PSTR("201612K%07d"), ESP.getChipId());
|
||||||
|
return String(serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
String wemo_UUID()
|
||||||
|
{
|
||||||
|
char uuid[26];
|
||||||
|
snprintf_P(uuid, sizeof(uuid), PSTR("Socket-1_0-%s"), wemo_serial().c_str());
|
||||||
|
return String(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wemo_respondToMSearch()
|
||||||
|
{
|
||||||
|
char message[TOPSZ], log[LOGSZ];
|
||||||
|
|
||||||
|
if (portUDP.beginPacket(portUDP.remoteIP(), portUDP.remotePort())) {
|
||||||
|
String response = FPSTR(WEMO_MSEARCH);
|
||||||
|
response.replace("{r1}", WiFi.localIP().toString());
|
||||||
|
response.replace("{r2}", wemo_UUID());
|
||||||
|
portUDP.write(response.c_str());
|
||||||
|
portUDP.endPacket();
|
||||||
|
snprintf_P(message, sizeof(message), PSTR("Response sent"));
|
||||||
|
} else {
|
||||||
|
snprintf_P(message, sizeof(message), PSTR("Failed to send response"));
|
||||||
|
}
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("UPnP: Wemo %s to %s:%d"),
|
||||||
|
message, portUDP.remoteIP().toString().c_str(), portUDP.remotePort());
|
||||||
|
addLog(LOG_LEVEL_DEBUG, log);
|
||||||
|
}
|
||||||
|
#endif // USE_WEMO_EMULATION
|
||||||
|
|
||||||
|
#ifdef USE_HUE_EMULATION
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Hue Bridge UPNP support routines
|
||||||
|
* Need to send 3 response packets with varying ST and USN
|
||||||
|
\*********************************************************************************************/
|
||||||
|
const char HUE_RESPONSE[] PROGMEM =
|
||||||
|
"HTTP/1.0 200 OK\r\n"
|
||||||
|
"HOST: 239.255.255.250:1900\r\n"
|
||||||
|
"CACHE-CONTROL: max-age=100\r\n"
|
||||||
|
"EXT:\r\n"
|
||||||
|
"LOCATION: http://{r1}:80/description.xml\r\n"
|
||||||
|
"SERVER: FreeRTOS/7.4.2 UPnP/1.0 IpBridge/1.15.0\r\n"
|
||||||
|
"hue-bridgeid: {r2}\r\n";
|
||||||
|
const char HUE_ST1[] PROGMEM =
|
||||||
|
"ST: upnp:rootdevice\r\n";
|
||||||
|
const char HUE_USN1[] PROGMEM =
|
||||||
|
"USN: uuid:{r3}::upnp:rootdevice\r\n"
|
||||||
|
"\r\n";
|
||||||
|
|
||||||
|
const char HUE_ST2[] PROGMEM =
|
||||||
|
"ST: uuid:{r3}\r\n";
|
||||||
|
const char HUE_USN2[] PROGMEM =
|
||||||
|
"USN: uuid:{r3}\r\n"
|
||||||
|
"\r\n";
|
||||||
|
|
||||||
|
const char HUE_ST3[] PROGMEM =
|
||||||
|
"ST: urn:schemas-upnp-org:device:basic:1\r\n";
|
||||||
|
|
||||||
|
String hue_bridgeid()
|
||||||
|
{
|
||||||
|
char bridgeid[16];
|
||||||
|
snprintf_P(bridgeid, sizeof(bridgeid), PSTR("5CCF7FFFFE%03X"), ESP.getChipId());
|
||||||
|
return String(bridgeid);
|
||||||
|
}
|
||||||
|
|
||||||
|
String hue_UUID()
|
||||||
|
{
|
||||||
|
char serial[36];
|
||||||
|
snprintf_P(serial, sizeof(serial), PSTR("f6543a06-da50-11ba-8d8f-5ccf7f%03x"), ESP.getChipId());
|
||||||
|
return String(serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hue_respondToMSearch()
|
||||||
|
{
|
||||||
|
char message[TOPSZ], log[LOGSZ];
|
||||||
|
|
||||||
|
if (portUDP.beginPacket(portUDP.remoteIP(), portUDP.remotePort())) {
|
||||||
|
String response = FPSTR(HUE_RESPONSE);
|
||||||
|
String response_st=FPSTR(HUE_ST1);
|
||||||
|
String response_usn=FPSTR(HUE_USN1);
|
||||||
|
response += response_st + response_usn;
|
||||||
|
response.replace("{r1}", WiFi.localIP().toString());
|
||||||
|
response.replace("{r2}", hue_bridgeid());
|
||||||
|
response.replace("{r3}", hue_UUID());
|
||||||
|
portUDP.write(response.c_str());
|
||||||
|
portUDP.endPacket();
|
||||||
|
snprintf_P(message, sizeof(message), PSTR("Response1 sent"));
|
||||||
|
// addLog(LOG_LEVEL_DEBUG_MORE, response.c_str());
|
||||||
|
|
||||||
|
response = FPSTR(HUE_RESPONSE);
|
||||||
|
response_st=FPSTR(HUE_ST2);
|
||||||
|
response_usn=FPSTR(HUE_USN2);
|
||||||
|
response += response_st + response_usn;
|
||||||
|
response.replace("{r1}", WiFi.localIP().toString());
|
||||||
|
response.replace("{r2}", hue_bridgeid());
|
||||||
|
response.replace("{r3}", hue_UUID());
|
||||||
|
portUDP.write(response.c_str());
|
||||||
|
portUDP.endPacket();
|
||||||
|
snprintf_P(message, sizeof(message), PSTR("Response2 sent"));
|
||||||
|
// addLog(LOG_LEVEL_DEBUG_MORE, response.c_str());
|
||||||
|
|
||||||
|
response = FPSTR(HUE_RESPONSE);
|
||||||
|
response_st=FPSTR(HUE_ST3);
|
||||||
|
response += response_st + response_usn;
|
||||||
|
response.replace("{r1}", WiFi.localIP().toString());
|
||||||
|
response.replace("{r2}", hue_bridgeid());
|
||||||
|
response.replace("{r3}", hue_UUID());
|
||||||
|
portUDP.write(response.c_str());
|
||||||
|
portUDP.endPacket();
|
||||||
|
snprintf_P(message, sizeof(message), PSTR("Response3 sent"));
|
||||||
|
// addLog(LOG_LEVEL_DEBUG_MORE, response.c_str());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
snprintf_P(message, sizeof(message), PSTR("Failed to send response"));
|
||||||
|
}
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("UPnP: HUE %s to %s:%d"),
|
||||||
|
message, portUDP.remoteIP().toString().c_str(), portUDP.remotePort());
|
||||||
|
addLog(LOG_LEVEL_DEBUG, log);
|
||||||
|
}
|
||||||
|
#endif // USE_HUE_EMULATION
|
||||||
|
|
||||||
|
/********************************************************************************************/
|
||||||
|
|
||||||
|
#if defined(USE_WEMO_EMULATION) || defined(USE_HUE_EMULATION)
|
||||||
|
boolean UDP_Disconnect()
|
||||||
|
{
|
||||||
|
if (udpConnected) {
|
||||||
|
WiFiUDP::stopAll();
|
||||||
|
addLog_P(LOG_LEVEL_DEBUG, PSTR("UPnP: Multicast disabled"));
|
||||||
|
udpConnected = false;
|
||||||
|
}
|
||||||
|
return udpConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean UDP_Connect()
|
||||||
|
{
|
||||||
|
if (!udpConnected) {
|
||||||
|
if (portUDP.beginMulticast(WiFi.localIP(), ipMulticast, portMulticast)) {
|
||||||
|
addLog_P(LOG_LEVEL_INFO, PSTR("UPnP: Multicast (re)joined"));
|
||||||
|
udpConnected = true;
|
||||||
|
} else {
|
||||||
|
addLog_P(LOG_LEVEL_INFO, PSTR("UPnP: Multicast join failed"));
|
||||||
|
udpConnected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return udpConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pollUDP()
|
||||||
|
{
|
||||||
|
if (udpConnected) {
|
||||||
|
if (portUDP.parsePacket()) {
|
||||||
|
int len = portUDP.read(packetBuffer, UDP_BUFFER_SIZE -1);
|
||||||
|
if (len > 0) packetBuffer[len] = 0;
|
||||||
|
String request = packetBuffer;
|
||||||
|
// addLog_P(LOG_LEVEL_DEBUG_MORE, packetBuffer);
|
||||||
|
if (request.indexOf("M-SEARCH") >= 0) {
|
||||||
|
#ifdef USE_WEMO_EMULATION
|
||||||
|
if (request.indexOf("urn:Belkin:device:**") > 0) {
|
||||||
|
wemo_respondToMSearch();
|
||||||
|
}
|
||||||
|
#endif // USE_WEMO_EMULATION
|
||||||
|
#ifdef USE_HUE_EMULATION
|
||||||
|
if (request.indexOf("ST: urn:schemas-upnp-org:device:basic:1") > 0 ||
|
||||||
|
request.indexOf("ST: upnp:rootdevice") > 0 ||
|
||||||
|
request.indexOf("ST: ssdp:all") > 0) {
|
||||||
|
hue_respondToMSearch();
|
||||||
|
}
|
||||||
|
#endif // USE_HUE_EMULATION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // USE_WEMO_EMULATION || USE_HUE_EMULATION
|
||||||
|
#endif // USE_WEMO_EMULATION || USE_HUE_EMULATION
|
||||||
|
|
|
@ -0,0 +1,465 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Theo Arends. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_WS2812
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* WS2812 Leds using NeopixelBus library
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#include <NeoPixelBus.h>
|
||||||
|
|
||||||
|
#ifdef USE_WS2812_DMA
|
||||||
|
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> *strip = NULL;
|
||||||
|
#else
|
||||||
|
NeoPixelBus<NeoGrbFeature, NeoEsp8266BitBang800KbpsMethod> *strip = NULL;
|
||||||
|
#endif // USE_WS2812_DMA
|
||||||
|
|
||||||
|
#define COLOR_SATURATION 254.0f
|
||||||
|
|
||||||
|
struct wsColor {
|
||||||
|
uint8_t red, green, blue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ColorScheme {
|
||||||
|
wsColor* colors;
|
||||||
|
uint8_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
wsColor incandescent[2] = { 255, 140, 20, 0, 0, 0 };
|
||||||
|
wsColor rgb[3] = { 255, 0, 0, 0, 255, 0, 0, 0, 255 };
|
||||||
|
wsColor christmas[2] = { 255, 0, 0, 0, 255, 0 };
|
||||||
|
wsColor hanukkah[2] = { 0, 0, 255, 255, 255, 255 };
|
||||||
|
wsColor kwanzaa[3] = { 255, 0, 0, 0, 0, 0, 0, 255, 0 };
|
||||||
|
wsColor rainbow[7] = { 255, 0, 0, 255, 128, 0, 255, 255, 0, 0, 255, 0, 0, 0, 255, 128, 0, 255, 255, 0, 255 };
|
||||||
|
wsColor fire[3] = { 255, 0, 0, 255, 102, 0, 255, 192, 0 };
|
||||||
|
ColorScheme schemes[7] = {
|
||||||
|
incandescent, 2,
|
||||||
|
rgb, 3,
|
||||||
|
christmas, 2,
|
||||||
|
hanukkah, 2,
|
||||||
|
kwanzaa, 3,
|
||||||
|
rainbow, 7,
|
||||||
|
fire, 3 };
|
||||||
|
|
||||||
|
uint8_t widthValues[5] = {
|
||||||
|
1, // Small
|
||||||
|
2, // Medium
|
||||||
|
4, // Large
|
||||||
|
8, // Largest
|
||||||
|
255 }; // All
|
||||||
|
uint8_t repeatValues[5] = {
|
||||||
|
8, // Small
|
||||||
|
6, // Medium
|
||||||
|
4, // Large
|
||||||
|
2, // Largest
|
||||||
|
1 }; // All
|
||||||
|
uint8_t speedValues[6] = {
|
||||||
|
0, // None
|
||||||
|
18, // Slowest
|
||||||
|
14, // Slower
|
||||||
|
10, // Slow
|
||||||
|
6, // Fast
|
||||||
|
2 }; // Fastest
|
||||||
|
|
||||||
|
uint8_t ledTable[] = {
|
||||||
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4,
|
||||||
|
4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8,
|
||||||
|
8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14,
|
||||||
|
14, 15, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22,
|
||||||
|
22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32,
|
||||||
|
33, 33, 34, 35, 36, 36, 37, 38, 39, 40, 40, 41, 42, 43, 44, 45,
|
||||||
|
46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
|
||||||
|
61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78,
|
||||||
|
80, 81, 82, 83, 85, 86, 87, 89, 90, 91, 93, 94, 95, 97, 98, 99,
|
||||||
|
101,102,104,105,107,108,110,111,113,114,116,117,119,121,122,124,
|
||||||
|
125,127,129,130,132,134,135,137,139,141,142,144,146,148,150,151,
|
||||||
|
153,155,157,159,161,163,165,166,168,170,172,174,176,178,180,182,
|
||||||
|
184,186,189,191,193,195,197,199,201,204,206,208,210,212,215,217,
|
||||||
|
219,221,224,226,228,231,233,235,238,240,243,245,248,250,253,255 };
|
||||||
|
|
||||||
|
uint8_t lany = 0;
|
||||||
|
RgbColor dcolor, tcolor, lcolor;
|
||||||
|
|
||||||
|
uint8_t wakeupDimmer = 0;
|
||||||
|
uint16_t wakeupCntr = 0;
|
||||||
|
unsigned long stripTimerCntr = 0; // Bars and Gradient
|
||||||
|
|
||||||
|
void ws2812_setDim(uint8_t myDimmer)
|
||||||
|
{
|
||||||
|
float newDim = 100 / (float)myDimmer;
|
||||||
|
float fmyRed = (float)sysCfg.ws_red / newDim;
|
||||||
|
float fmyGrn = (float)sysCfg.ws_green / newDim;
|
||||||
|
float fmyBlu = (float)sysCfg.ws_blue / newDim;
|
||||||
|
dcolor.R = (uint8_t)fmyRed;
|
||||||
|
dcolor.G = (uint8_t)fmyGrn;
|
||||||
|
dcolor.B = (uint8_t)fmyBlu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_setColor(uint16_t led, char* colstr)
|
||||||
|
{
|
||||||
|
HtmlColor hcolor;
|
||||||
|
char log[LOGSZ], lcolstr[8];
|
||||||
|
|
||||||
|
snprintf_P(lcolstr, sizeof(lcolstr), PSTR("#%s"), colstr);
|
||||||
|
uint8_t result = hcolor.Parse<HtmlColorNames>((char *)lcolstr, 7);
|
||||||
|
if (result) {
|
||||||
|
if (led) {
|
||||||
|
strip->SetPixelColor(led -1, RgbColor(hcolor)); // Led 1 is strip Led 0 -> substract offset 1
|
||||||
|
strip->Show();
|
||||||
|
} else {
|
||||||
|
dcolor = RgbColor(hcolor);
|
||||||
|
|
||||||
|
// snprintf_P(log, sizeof(log), PSTR("DBG: Red %02X, Green %02X, Blue %02X"), dcolor.R, dcolor.G, dcolor.B);
|
||||||
|
// addLog(LOG_LEVEL_DEBUG, log);
|
||||||
|
|
||||||
|
uint16_t temp = dcolor.R;
|
||||||
|
if (temp < dcolor.G) temp = dcolor.G;
|
||||||
|
if (temp < dcolor.B) temp = dcolor.B;
|
||||||
|
float mDim = (float)temp / 2.55;
|
||||||
|
sysCfg.ws_dimmer = (uint8_t)mDim;
|
||||||
|
|
||||||
|
float newDim = 100 / mDim;
|
||||||
|
float fmyRed = (float)dcolor.R * newDim;
|
||||||
|
float fmyGrn = (float)dcolor.G * newDim;
|
||||||
|
float fmyBlu = (float)dcolor.B * newDim;
|
||||||
|
sysCfg.ws_red = (uint8_t)fmyRed;
|
||||||
|
sysCfg.ws_green = (uint8_t)fmyGrn;
|
||||||
|
sysCfg.ws_blue = (uint8_t)fmyBlu;
|
||||||
|
|
||||||
|
lany = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_replaceHSB(String *response)
|
||||||
|
{
|
||||||
|
ws2812_setDim(sysCfg.ws_dimmer);
|
||||||
|
HsbColor hsb=HsbColor(dcolor);
|
||||||
|
response->replace("{h}", String((uint16_t)(65535.0f * hsb.H)));
|
||||||
|
response->replace("{s}", String((uint8_t)(COLOR_SATURATION * hsb.S)));
|
||||||
|
response->replace("{b}", String((uint8_t)(COLOR_SATURATION * hsb.B)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_changeBrightness(uint8_t bri)
|
||||||
|
{
|
||||||
|
char rgb[7];
|
||||||
|
|
||||||
|
//sysCfg.ws_ledtable=1; // Switch on Gamma Correction for "natural" brightness controll
|
||||||
|
ws2812_setDim(sysCfg.ws_dimmer);
|
||||||
|
HsbColor hsb = HsbColor(dcolor);
|
||||||
|
if (!bri) bri=1;
|
||||||
|
if (bri==255) bri=252;
|
||||||
|
hsb.B=(float)(bri/COLOR_SATURATION);
|
||||||
|
RgbColor tmp = RgbColor(hsb);
|
||||||
|
sprintf(rgb,"%02X%02X%02X", tmp.R, tmp.G, tmp.B);
|
||||||
|
ws2812_setColor(0,rgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_getColor(uint16_t led, char* svalue, uint16_t ssvalue)
|
||||||
|
{
|
||||||
|
RgbColor mcolor;
|
||||||
|
char stemp[20];
|
||||||
|
|
||||||
|
if (led) {
|
||||||
|
mcolor = strip->GetPixelColor(led -1);
|
||||||
|
snprintf_P(stemp, sizeof(stemp), PSTR("Led%d"), led);
|
||||||
|
} else {
|
||||||
|
ws2812_setDim(sysCfg.ws_dimmer);
|
||||||
|
mcolor = dcolor;
|
||||||
|
snprintf_P(stemp, sizeof(stemp), PSTR("Color"));
|
||||||
|
}
|
||||||
|
uint32_t color = (uint32_t)mcolor.R << 16;
|
||||||
|
color += (uint32_t)mcolor.G << 8;
|
||||||
|
color += (uint32_t)mcolor.B;
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("{\"%s\":\"%06X\"}"), stemp, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_stripShow()
|
||||||
|
{
|
||||||
|
RgbColor c;
|
||||||
|
|
||||||
|
if (sysCfg.ws_ledtable) {
|
||||||
|
for (uint16_t i = 0; i < sysCfg.ws_pixels; i++) {
|
||||||
|
c = strip->GetPixelColor(i);
|
||||||
|
strip->SetPixelColor(i, RgbColor(ledTable[c.R], ledTable[c.G], ledTable[c.B]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strip->Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_resetWakupState()
|
||||||
|
{
|
||||||
|
wakeupDimmer = 0;
|
||||||
|
wakeupCntr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_resetStripTimer()
|
||||||
|
{
|
||||||
|
stripTimerCntr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mod(int a, int b)
|
||||||
|
{
|
||||||
|
int ret = a % b;
|
||||||
|
if (ret < 0) ret += b;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_clock()
|
||||||
|
{
|
||||||
|
RgbColor c;
|
||||||
|
|
||||||
|
strip->ClearTo(0); // Reset strip
|
||||||
|
float newDim = 100 / (float)sysCfg.ws_dimmer;
|
||||||
|
float f1 = 255 / newDim;
|
||||||
|
uint8_t i1 = (uint8_t)f1;
|
||||||
|
float f2 = 127 / newDim;
|
||||||
|
uint8_t i2 = (uint8_t)f2;
|
||||||
|
float f3 = 63 / newDim;
|
||||||
|
uint8_t i3 = (uint8_t)f3;
|
||||||
|
|
||||||
|
int j = sysCfg.ws_pixels;
|
||||||
|
int clksize = 600 / j;
|
||||||
|
int i = (rtcTime.Second * 10) / clksize;
|
||||||
|
|
||||||
|
c = strip->GetPixelColor(mod(i, j)); c.B = i1; strip->SetPixelColor(mod(i, j), c);
|
||||||
|
i = (rtcTime.Minute * 10) / clksize;
|
||||||
|
c = strip->GetPixelColor(mod(i -1, j)); c.G = i3; strip->SetPixelColor(mod(i -1, j), c);
|
||||||
|
c = strip->GetPixelColor(mod(i, j)); c.G = i1; strip->SetPixelColor(mod(i, j), c);
|
||||||
|
c = strip->GetPixelColor(mod(i +1, j)); c.G = i3; strip->SetPixelColor(mod(i +1, j), c);
|
||||||
|
i = (rtcTime.Hour % 12) * (50 / clksize);
|
||||||
|
c = strip->GetPixelColor(mod(i -2, j)); c.R = i3; strip->SetPixelColor(mod(i -2, j), c);
|
||||||
|
c = strip->GetPixelColor(mod(i -1, j)); c.R = i2; strip->SetPixelColor(mod(i -1, j), c);
|
||||||
|
c = strip->GetPixelColor(mod(i, j)); c.R = i1; strip->SetPixelColor(mod(i, j), c);
|
||||||
|
c = strip->GetPixelColor(mod(i +1, j)); c.R = i2; strip->SetPixelColor(mod(i +1, j), c);
|
||||||
|
c = strip->GetPixelColor(mod(i +2, j)); c.R = i3; strip->SetPixelColor(mod(i +2, j), c);
|
||||||
|
ws2812_stripShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_gradientColor(struct wsColor* mColor, uint8_t range, uint8_t gradRange, uint8_t i)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Compute the color of a pixel at position i using a gradient of the color scheme.
|
||||||
|
* This function is used internally by the gradient function.
|
||||||
|
*/
|
||||||
|
ColorScheme scheme = schemes[sysCfg.ws_scheme -3];
|
||||||
|
uint8_t curRange = i / range;
|
||||||
|
uint8_t rangeIndex = i % range;
|
||||||
|
uint8_t colorIndex = rangeIndex / gradRange;
|
||||||
|
uint8_t start = colorIndex;
|
||||||
|
uint8_t end = colorIndex +1;
|
||||||
|
if (curRange % 2 != 0) {
|
||||||
|
start = (scheme.count -1) - start;
|
||||||
|
end = (scheme.count -1) - end;
|
||||||
|
}
|
||||||
|
float newDim = 100 / (float)sysCfg.ws_dimmer;
|
||||||
|
float fmyRed = (float)map(rangeIndex % gradRange, 0, gradRange, scheme.colors[start].red, scheme.colors[end].red) / newDim;
|
||||||
|
float fmyGrn = (float)map(rangeIndex % gradRange, 0, gradRange, scheme.colors[start].green, scheme.colors[end].green) / newDim;
|
||||||
|
float fmyBlu = (float)map(rangeIndex % gradRange, 0, gradRange, scheme.colors[start].blue, scheme.colors[end].blue) / newDim;
|
||||||
|
mColor->red = (uint8_t)fmyRed;
|
||||||
|
mColor->green = (uint8_t)fmyGrn;
|
||||||
|
mColor->blue = (uint8_t)fmyBlu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_gradient()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This routine courtesy Tony DiCola (Adafruit)
|
||||||
|
* Display a gradient of colors for the current color scheme.
|
||||||
|
* Repeat is the number of repetitions of the gradient (pick a multiple of 2 for smooth looping of the gradient).
|
||||||
|
*/
|
||||||
|
RgbColor c;
|
||||||
|
|
||||||
|
ColorScheme scheme = schemes[sysCfg.ws_scheme -3];
|
||||||
|
if (scheme.count < 2) return;
|
||||||
|
|
||||||
|
uint8_t repeat = repeatValues[sysCfg.ws_width]; // number of scheme.count per ledcount
|
||||||
|
uint8_t range = (uint8_t)ceil((float)sysCfg.ws_pixels / (float)repeat);
|
||||||
|
uint8_t gradRange = (uint8_t)ceil((float)range / (float)(scheme.count - 1));
|
||||||
|
uint8_t offset = speedValues[sysCfg.ws_speed] > 0 ? stripTimerCntr / speedValues[sysCfg.ws_speed] : 0;
|
||||||
|
|
||||||
|
wsColor oldColor, currentColor;
|
||||||
|
ws2812_gradientColor(&oldColor, range, gradRange, offset);
|
||||||
|
currentColor = oldColor;
|
||||||
|
for (uint16_t i = 0; i < sysCfg.ws_pixels; i++) {
|
||||||
|
if (repeatValues[sysCfg.ws_width] > 1) ws2812_gradientColor(¤tColor, range, gradRange, i +offset);
|
||||||
|
if (sysCfg.ws_speed > 0) {
|
||||||
|
// Blend old and current color based on time for smooth movement.
|
||||||
|
c.R = map(stripTimerCntr % speedValues[sysCfg.ws_speed], 0, speedValues[sysCfg.ws_speed], oldColor.red, currentColor.red);
|
||||||
|
c.G = map(stripTimerCntr % speedValues[sysCfg.ws_speed], 0, speedValues[sysCfg.ws_speed], oldColor.green, currentColor.green);
|
||||||
|
c.B = map(stripTimerCntr % speedValues[sysCfg.ws_speed], 0, speedValues[sysCfg.ws_speed], oldColor.blue, currentColor.blue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// No animation, just use the current color.
|
||||||
|
c.R = currentColor.red;
|
||||||
|
c.G = currentColor.green;
|
||||||
|
c.B = currentColor.blue;
|
||||||
|
}
|
||||||
|
strip->SetPixelColor(i, c);
|
||||||
|
oldColor = currentColor;
|
||||||
|
}
|
||||||
|
ws2812_stripShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_bars()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This routine courtesy Tony DiCola (Adafruit)
|
||||||
|
* Display solid bars of color for the current color scheme.
|
||||||
|
* Width is the width of each bar in pixels/lights.
|
||||||
|
*/
|
||||||
|
RgbColor c;
|
||||||
|
uint16_t i;
|
||||||
|
|
||||||
|
ColorScheme scheme = schemes[sysCfg.ws_scheme -3];
|
||||||
|
|
||||||
|
uint8_t maxSize = sysCfg.ws_pixels / scheme.count;
|
||||||
|
if (widthValues[sysCfg.ws_width] > maxSize) maxSize = 0;
|
||||||
|
|
||||||
|
uint8_t offset = speedValues[sysCfg.ws_speed] > 0 ? stripTimerCntr / speedValues[sysCfg.ws_speed] : 0;
|
||||||
|
|
||||||
|
wsColor mcolor[scheme.count];
|
||||||
|
memcpy(mcolor, scheme.colors, sizeof(mcolor));
|
||||||
|
float newDim = 100 / (float)sysCfg.ws_dimmer;
|
||||||
|
for (i = 0; i < scheme.count; i++) {
|
||||||
|
float fmyRed = (float)mcolor[i].red / newDim;
|
||||||
|
float fmyGrn = (float)mcolor[i].green / newDim;
|
||||||
|
float fmyBlu = (float)mcolor[i].blue / newDim;
|
||||||
|
mcolor[i].red = (uint8_t)fmyRed;
|
||||||
|
mcolor[i].green = (uint8_t)fmyGrn;
|
||||||
|
mcolor[i].blue = (uint8_t)fmyBlu;
|
||||||
|
}
|
||||||
|
uint8_t colorIndex = offset % scheme.count;
|
||||||
|
for (i = 0; i < sysCfg.ws_pixels; i++) {
|
||||||
|
if (maxSize)
|
||||||
|
colorIndex = ((i + offset) % (scheme.count * widthValues[sysCfg.ws_width])) / widthValues[sysCfg.ws_width];
|
||||||
|
c.R = mcolor[colorIndex].red;
|
||||||
|
c.G = mcolor[colorIndex].green;
|
||||||
|
c.B = mcolor[colorIndex].blue;
|
||||||
|
strip->SetPixelColor(i, c);
|
||||||
|
}
|
||||||
|
ws2812_stripShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_animate()
|
||||||
|
{
|
||||||
|
char log[LOGSZ];
|
||||||
|
uint8_t fadeValue;
|
||||||
|
|
||||||
|
stripTimerCntr++;
|
||||||
|
if (power == 0) { // Power Off
|
||||||
|
stripTimerCntr = 0;
|
||||||
|
tcolor = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (sysCfg.ws_scheme) {
|
||||||
|
case 0: // Power On
|
||||||
|
ws2812_setDim(sysCfg.ws_dimmer);
|
||||||
|
if (sysCfg.ws_fade == 0) {
|
||||||
|
tcolor = dcolor;
|
||||||
|
} else {
|
||||||
|
if (tcolor != dcolor) {
|
||||||
|
if (tcolor.R < dcolor.R) tcolor.R += ((dcolor.R - tcolor.R) >> sysCfg.ws_speed) +1;
|
||||||
|
if (tcolor.G < dcolor.G) tcolor.G += ((dcolor.G - tcolor.G) >> sysCfg.ws_speed) +1;
|
||||||
|
if (tcolor.B < dcolor.B) tcolor.B += ((dcolor.B - tcolor.B) >> sysCfg.ws_speed) +1;
|
||||||
|
if (tcolor.R > dcolor.R) tcolor.R -= ((tcolor.R - dcolor.R) >> sysCfg.ws_speed) +1;
|
||||||
|
if (tcolor.G > dcolor.G) tcolor.G -= ((tcolor.G - dcolor.G) >> sysCfg.ws_speed) +1;
|
||||||
|
if (tcolor.B > dcolor.B) tcolor.B -= ((tcolor.B - dcolor.B) >> sysCfg.ws_speed) +1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: // Wake up light
|
||||||
|
wakeupCntr++;
|
||||||
|
if (wakeupDimmer == 0) {
|
||||||
|
tcolor = 0;
|
||||||
|
wakeupDimmer++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (wakeupCntr > ((sysCfg.ws_wakeup * STATES) / sysCfg.ws_dimmer)) {
|
||||||
|
wakeupCntr = 0;
|
||||||
|
wakeupDimmer++;
|
||||||
|
if (wakeupDimmer <= sysCfg.ws_dimmer) {
|
||||||
|
ws2812_setDim(wakeupDimmer);
|
||||||
|
tcolor = dcolor;
|
||||||
|
} else
|
||||||
|
sysCfg.ws_scheme = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: // Clock
|
||||||
|
if ((state == (STATES/10)*2) || (lany != 2)) ws2812_clock();
|
||||||
|
lany = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (sysCfg.ws_fade == 1) ws2812_gradient(); else ws2812_bars();
|
||||||
|
lany = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sysCfg.ws_scheme <= 1) || (!(power &1))) {
|
||||||
|
if ((lcolor != tcolor) || lany) {
|
||||||
|
lany = 0;
|
||||||
|
lcolor = tcolor;
|
||||||
|
|
||||||
|
// snprintf_P(log, sizeof(log), PSTR("DBG: StripPixels %d, CfgPixels %d, Red %02X, Green %02X, Blue %02X"), strip->PixelCount(), sysCfg.ws_pixels, lcolor.R, lcolor.G, lcolor.B);
|
||||||
|
// addLog(LOG_LEVEL_DEBUG, log);
|
||||||
|
|
||||||
|
if (sysCfg.ws_ledtable) {
|
||||||
|
for (uint16_t i = 0; i < sysCfg.ws_pixels; i++) strip->SetPixelColor(i, RgbColor(ledTable[lcolor.R],ledTable[lcolor.G],ledTable[lcolor.B]));
|
||||||
|
} else {
|
||||||
|
for (uint16_t i = 0; i < sysCfg.ws_pixels; i++) strip->SetPixelColor(i, lcolor);
|
||||||
|
}
|
||||||
|
strip->Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_update()
|
||||||
|
{
|
||||||
|
lany = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_pixels()
|
||||||
|
{
|
||||||
|
strip->ClearTo(0);
|
||||||
|
strip->Show();
|
||||||
|
tcolor = 0;
|
||||||
|
lany = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_init()
|
||||||
|
{
|
||||||
|
#ifdef USE_WS2812_DMA
|
||||||
|
strip = new NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod>(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use.
|
||||||
|
#else
|
||||||
|
strip = new NeoPixelBus<NeoGrbFeature, NeoEsp8266BitBang800KbpsMethod>(WS2812_MAX_LEDS, pin[GPIO_WS2812]);
|
||||||
|
#endif // USE_WS2812_DMA
|
||||||
|
strip->Begin();
|
||||||
|
ws2812_pixels();
|
||||||
|
}
|
||||||
|
#endif // USE_WS2812
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Theo Arends. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_I2C
|
||||||
|
#ifdef USE_BH1750
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* BH1750 - Ambient Light Intensity
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define BH1750_ADDR1 0x23
|
||||||
|
#define BH1750_ADDR2 0x5C
|
||||||
|
|
||||||
|
#define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10 // Start measurement at 1lx resolution. Measurement time is approx 120ms.
|
||||||
|
|
||||||
|
uint8_t bh1750addr, bh1750type = 0;
|
||||||
|
char bh1750stype[7];
|
||||||
|
|
||||||
|
uint16_t bh1750_readLux(void)
|
||||||
|
{
|
||||||
|
Wire.requestFrom(bh1750addr, (uint8_t)2);
|
||||||
|
byte msb = Wire.read();
|
||||||
|
byte lsb = Wire.read();
|
||||||
|
uint16_t value = ((msb << 8) | lsb) / 1.2;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean bh1750_detect()
|
||||||
|
{
|
||||||
|
if (bh1750type) return true;
|
||||||
|
|
||||||
|
char log[LOGSZ];
|
||||||
|
uint8_t status;
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
bh1750addr = BH1750_ADDR1;
|
||||||
|
Wire.beginTransmission(bh1750addr);
|
||||||
|
Wire.write(BH1750_CONTINUOUS_HIGH_RES_MODE);
|
||||||
|
status = Wire.endTransmission();
|
||||||
|
if (status) {
|
||||||
|
bh1750addr = BH1750_ADDR2;
|
||||||
|
Wire.beginTransmission(bh1750addr);
|
||||||
|
Wire.write(BH1750_CONTINUOUS_HIGH_RES_MODE);
|
||||||
|
status = Wire.endTransmission();
|
||||||
|
}
|
||||||
|
if (!status) {
|
||||||
|
success = true;
|
||||||
|
bh1750type = 1;
|
||||||
|
snprintf_P(bh1750stype, sizeof(bh1750stype), PSTR("BH1750"));
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("I2C: %s found at address 0x%x"), bh1750stype, bh1750addr);
|
||||||
|
addLog(LOG_LEVEL_DEBUG, log);
|
||||||
|
} else {
|
||||||
|
bh1750type = 0;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Presentation
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
void bh1750_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx)
|
||||||
|
{
|
||||||
|
if (!bh1750type) return;
|
||||||
|
|
||||||
|
uint16_t l = bh1750_readLux();
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Illuminance\":%d}"), svalue, bh1750stype, l);
|
||||||
|
*djson = 1;
|
||||||
|
#ifdef USE_DOMOTICZ
|
||||||
|
domoticz_sensor5(l);
|
||||||
|
#endif // USE_DOMOTICZ
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
String bh1750_webPresent()
|
||||||
|
{
|
||||||
|
String page = "";
|
||||||
|
if (bh1750type) {
|
||||||
|
uint16_t l = bh1750_readLux();
|
||||||
|
page += F("<tr><td>Illuminance: </td><td>"); page += String(l); page += F(" lx</td></tr>");
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
#endif // USE_BH1750
|
||||||
|
#endif // USE_I2C
|
||||||
|
|
|
@ -0,0 +1,477 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Heiko Krupp and Theo Arends. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_I2C
|
||||||
|
#ifdef USE_BMP
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* BMP085, BMP180, BMP280, BME280 - Pressure and Temperature and Humidy (BME280 only)
|
||||||
|
*
|
||||||
|
* Source: Heiko Krupp and Adafruit Industries
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define BMP_ADDR 0x77
|
||||||
|
|
||||||
|
#define BMP180_CHIPID 0x55
|
||||||
|
#define BMP280_CHIPID 0x58
|
||||||
|
#define BME280_CHIPID 0x60
|
||||||
|
|
||||||
|
#define BMP_REGISTER_CHIPID 0xD0
|
||||||
|
|
||||||
|
uint8_t bmpaddr, bmptype = 0;
|
||||||
|
char bmpstype[7];
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* BMP085 and BME180
|
||||||
|
*
|
||||||
|
* Programmer : Heiko Krupp with changes from Theo Arends
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define BMP180_REG_CONTROL 0xF4
|
||||||
|
#define BMP180_REG_RESULT 0xF6
|
||||||
|
#define BMP180_TEMPERATURE 0x2E
|
||||||
|
#define BMP180_PRESSURE3 0xF4 // Max. oversampling -> OSS = 3
|
||||||
|
|
||||||
|
#define BMP180_AC1 0xAA
|
||||||
|
#define BMP180_AC2 0xAC
|
||||||
|
#define BMP180_AC3 0xAE
|
||||||
|
#define BMP180_AC4 0xB0
|
||||||
|
#define BMP180_AC5 0xB2
|
||||||
|
#define BMP180_AC6 0xB4
|
||||||
|
#define BMP180_VB1 0xB6
|
||||||
|
#define BMP180_VB2 0xB8
|
||||||
|
#define BMP180_MB 0xBA
|
||||||
|
#define BMP180_MC 0xBC
|
||||||
|
#define BMP180_MD 0xBE
|
||||||
|
|
||||||
|
#define BMP180_OSS 3
|
||||||
|
|
||||||
|
int16_t cal_ac1,cal_ac2,cal_ac3,cal_b1,cal_b2,cal_mc,cal_md;
|
||||||
|
uint16_t cal_ac4,cal_ac5,cal_ac6;
|
||||||
|
int32_t bmp180_b5 = 0;
|
||||||
|
|
||||||
|
boolean bmp180_calibration()
|
||||||
|
{
|
||||||
|
cal_ac1 = i2c_read16(bmpaddr, BMP180_AC1);
|
||||||
|
cal_ac2 = i2c_read16(bmpaddr, BMP180_AC2);
|
||||||
|
cal_ac3 = i2c_read16(bmpaddr, BMP180_AC3);
|
||||||
|
cal_ac4 = i2c_read16(bmpaddr, BMP180_AC4);
|
||||||
|
cal_ac5 = i2c_read16(bmpaddr, BMP180_AC5);
|
||||||
|
cal_ac6 = i2c_read16(bmpaddr, BMP180_AC6);
|
||||||
|
cal_b1 = i2c_read16(bmpaddr, BMP180_VB1);
|
||||||
|
cal_b2 = i2c_read16(bmpaddr, BMP180_VB2);
|
||||||
|
cal_mc = i2c_read16(bmpaddr, BMP180_MC);
|
||||||
|
cal_md = i2c_read16(bmpaddr, BMP180_MD);
|
||||||
|
|
||||||
|
// Check for Errors in calibration data. Value never is 0x0000 or 0xFFFF
|
||||||
|
if(!cal_ac1 | !cal_ac2 | !cal_ac3 | !cal_ac4 | !cal_ac5 |
|
||||||
|
!cal_ac6 | !cal_b1 | !cal_b2 | !cal_mc | !cal_md)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if((cal_ac1==0xFFFF)|
|
||||||
|
(cal_ac2==0xFFFF)|
|
||||||
|
(cal_ac3==0xFFFF)|
|
||||||
|
(cal_ac4==0xFFFF)|
|
||||||
|
(cal_ac5==0xFFFF)|
|
||||||
|
(cal_ac6==0xFFFF)|
|
||||||
|
(cal_b1==0xFFFF)|
|
||||||
|
(cal_b2==0xFFFF)|
|
||||||
|
(cal_mc==0xFFFF)|
|
||||||
|
(cal_md==0xFFFF))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double bmp180_readTemperature()
|
||||||
|
{
|
||||||
|
i2c_write8(bmpaddr, BMP180_REG_CONTROL, BMP180_TEMPERATURE);
|
||||||
|
delay(5); // 5ms conversion time
|
||||||
|
int ut = i2c_read16(bmpaddr, BMP180_REG_RESULT);
|
||||||
|
int32_t x1 = (ut - (int32_t)cal_ac6) * ((int32_t)cal_ac5) >> 15;
|
||||||
|
int32_t x2 = ((int32_t)cal_mc << 11) / (x1+(int32_t)cal_md);
|
||||||
|
bmp180_b5=x1+x2;
|
||||||
|
|
||||||
|
return ((bmp180_b5+8)>>4)/10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double bmp180_readPressure()
|
||||||
|
{
|
||||||
|
int32_t p;
|
||||||
|
uint8_t msb,lsb,xlsb;
|
||||||
|
|
||||||
|
i2c_write8(bmpaddr, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution
|
||||||
|
delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution
|
||||||
|
uint32_t up = i2c_read24(bmpaddr, BMP180_REG_RESULT);
|
||||||
|
up >>= (8 - BMP180_OSS);
|
||||||
|
|
||||||
|
int32_t b6 = bmp180_b5 - 4000;
|
||||||
|
int32_t x1 = ((int32_t)cal_b2 * ( (b6 * b6)>>12 )) >> 11;
|
||||||
|
int32_t x2 = ((int32_t)cal_ac2 * b6) >> 11;
|
||||||
|
int32_t x3 = x1 + x2;
|
||||||
|
int32_t b3 = ((((int32_t)cal_ac1*4 + x3) << BMP180_OSS) + 2)>>2;
|
||||||
|
|
||||||
|
x1 = ((int32_t)cal_ac3 * b6) >> 13;
|
||||||
|
x2 = ((int32_t)cal_b1 * ((b6 * b6) >> 12)) >> 16;
|
||||||
|
x3 = ((x1 + x2) + 2) >> 2;
|
||||||
|
uint32_t b4 = ((uint32_t)cal_ac4 * (uint32_t)(x3 + 32768)) >> 15;
|
||||||
|
uint32_t b7 = ((uint32_t)up - b3) * (uint32_t)( 50000UL >> BMP180_OSS);
|
||||||
|
|
||||||
|
if (b7 < 0x80000000) {
|
||||||
|
p = (b7 * 2) / b4;
|
||||||
|
} else {
|
||||||
|
p = (b7 / b4) * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
x1 = (p >> 8) * (p >> 8);
|
||||||
|
x1 = (x1 * 3038) >> 16;
|
||||||
|
x2 = (-7357 * p) >> 16;
|
||||||
|
|
||||||
|
p += ((x1 + x2 + (int32_t)3791)>>4);
|
||||||
|
return p/100.0; // convert to mbar
|
||||||
|
}
|
||||||
|
|
||||||
|
double bmp180_calcSealevelPressure(float pAbs, float altitude_meters)
|
||||||
|
{
|
||||||
|
double pressure = pAbs*100.0;
|
||||||
|
return (double)(pressure / pow(1.0-altitude_meters/44330, 5.255))/100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* BMP280 and BME280
|
||||||
|
*
|
||||||
|
* Programmer : BMP280/BME280 Datasheet and Adafruit with changes by Theo Arends
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define BME280_REGISTER_CONTROLHUMID 0xF2
|
||||||
|
#define BME280_REGISTER_CONTROL 0xF4
|
||||||
|
#define BME280_REGISTER_PRESSUREDATA 0xF7
|
||||||
|
#define BME280_REGISTER_TEMPDATA 0xFA
|
||||||
|
#define BME280_REGISTER_HUMIDDATA 0xFD
|
||||||
|
|
||||||
|
#define BME280_REGISTER_DIG_T1 0x88
|
||||||
|
#define BME280_REGISTER_DIG_T2 0x8A
|
||||||
|
#define BME280_REGISTER_DIG_T3 0x8C
|
||||||
|
#define BME280_REGISTER_DIG_P1 0x8E
|
||||||
|
#define BME280_REGISTER_DIG_P2 0x90
|
||||||
|
#define BME280_REGISTER_DIG_P3 0x92
|
||||||
|
#define BME280_REGISTER_DIG_P4 0x94
|
||||||
|
#define BME280_REGISTER_DIG_P5 0x96
|
||||||
|
#define BME280_REGISTER_DIG_P6 0x98
|
||||||
|
#define BME280_REGISTER_DIG_P7 0x9A
|
||||||
|
#define BME280_REGISTER_DIG_P8 0x9C
|
||||||
|
#define BME280_REGISTER_DIG_P9 0x9E
|
||||||
|
#define BME280_REGISTER_DIG_H1 0xA1
|
||||||
|
#define BME280_REGISTER_DIG_H2 0xE1
|
||||||
|
#define BME280_REGISTER_DIG_H3 0xE3
|
||||||
|
#define BME280_REGISTER_DIG_H4 0xE4
|
||||||
|
#define BME280_REGISTER_DIG_H5 0xE5
|
||||||
|
#define BME280_REGISTER_DIG_H6 0xE7
|
||||||
|
|
||||||
|
struct bme280_calib_data
|
||||||
|
{
|
||||||
|
uint16_t dig_T1;
|
||||||
|
int16_t dig_T2;
|
||||||
|
int16_t dig_T3;
|
||||||
|
uint16_t dig_P1;
|
||||||
|
int16_t dig_P2;
|
||||||
|
int16_t dig_P3;
|
||||||
|
int16_t dig_P4;
|
||||||
|
int16_t dig_P5;
|
||||||
|
int16_t dig_P6;
|
||||||
|
int16_t dig_P7;
|
||||||
|
int16_t dig_P8;
|
||||||
|
int16_t dig_P9;
|
||||||
|
uint8_t dig_H1;
|
||||||
|
int16_t dig_H2;
|
||||||
|
uint8_t dig_H3;
|
||||||
|
int16_t dig_H4;
|
||||||
|
int16_t dig_H5;
|
||||||
|
int8_t dig_H6;
|
||||||
|
} _bme280_calib;
|
||||||
|
|
||||||
|
int32_t t_fine;
|
||||||
|
|
||||||
|
boolean bmp280_calibrate()
|
||||||
|
{
|
||||||
|
// if (i2c_read8(bmpaddr, BMP_REGISTER_CHIPID) != BMP280_CHIPID) return false;
|
||||||
|
|
||||||
|
_bme280_calib.dig_T1 = i2c_read16_LE(bmpaddr, BME280_REGISTER_DIG_T1);
|
||||||
|
_bme280_calib.dig_T2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_T2);
|
||||||
|
_bme280_calib.dig_T3 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_T3);
|
||||||
|
_bme280_calib.dig_P1 = i2c_read16_LE(bmpaddr, BME280_REGISTER_DIG_P1);
|
||||||
|
_bme280_calib.dig_P2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P2);
|
||||||
|
_bme280_calib.dig_P3 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P3);
|
||||||
|
_bme280_calib.dig_P4 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P4);
|
||||||
|
_bme280_calib.dig_P5 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P5);
|
||||||
|
_bme280_calib.dig_P6 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P6);
|
||||||
|
_bme280_calib.dig_P7 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P7);
|
||||||
|
_bme280_calib.dig_P8 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P8);
|
||||||
|
_bme280_calib.dig_P9 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P9);
|
||||||
|
|
||||||
|
// i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0x3F); // Temp 1x oversampling, Press 16x oversampling, normal mode (Adafruit)
|
||||||
|
i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit)
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean bme280_calibrate()
|
||||||
|
{
|
||||||
|
// if (i2c_read8(bmpaddr, BMP_REGISTER_CHIPID) != BME280_CHIPID) return false;
|
||||||
|
|
||||||
|
_bme280_calib.dig_T1 = i2c_read16_LE(bmpaddr, BME280_REGISTER_DIG_T1);
|
||||||
|
_bme280_calib.dig_T2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_T2);
|
||||||
|
_bme280_calib.dig_T3 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_T3);
|
||||||
|
_bme280_calib.dig_P1 = i2c_read16_LE(bmpaddr, BME280_REGISTER_DIG_P1);
|
||||||
|
_bme280_calib.dig_P2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P2);
|
||||||
|
_bme280_calib.dig_P3 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P3);
|
||||||
|
_bme280_calib.dig_P4 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P4);
|
||||||
|
_bme280_calib.dig_P5 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P5);
|
||||||
|
_bme280_calib.dig_P6 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P6);
|
||||||
|
_bme280_calib.dig_P7 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P7);
|
||||||
|
_bme280_calib.dig_P8 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P8);
|
||||||
|
_bme280_calib.dig_P9 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P9);
|
||||||
|
_bme280_calib.dig_H1 = i2c_read8(bmpaddr, BME280_REGISTER_DIG_H1);
|
||||||
|
_bme280_calib.dig_H2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_H2);
|
||||||
|
_bme280_calib.dig_H3 = i2c_read8(bmpaddr, BME280_REGISTER_DIG_H3);
|
||||||
|
_bme280_calib.dig_H4 = (i2c_read8(bmpaddr, BME280_REGISTER_DIG_H4) << 4) | (i2c_read8(bmpaddr, BME280_REGISTER_DIG_H4 + 1) & 0xF);
|
||||||
|
_bme280_calib.dig_H5 = (i2c_read8(bmpaddr, BME280_REGISTER_DIG_H5 + 1) << 4) | (i2c_read8(bmpaddr, BME280_REGISTER_DIG_H5) >> 4);
|
||||||
|
_bme280_calib.dig_H6 = (int8_t)i2c_read8(bmpaddr, BME280_REGISTER_DIG_H6);
|
||||||
|
|
||||||
|
// Set before CONTROL_meas (DS 5.4.3)
|
||||||
|
i2c_write8(bmpaddr, BME280_REGISTER_CONTROLHUMID, 0x05); // 16x oversampling (Adafruit)
|
||||||
|
i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit)
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double bmp280_readTemperature(void)
|
||||||
|
{
|
||||||
|
int32_t var1, var2;
|
||||||
|
|
||||||
|
int32_t adc_T = i2c_read24(bmpaddr, BME280_REGISTER_TEMPDATA);
|
||||||
|
adc_T >>= 4;
|
||||||
|
|
||||||
|
var1 = ((((adc_T>>3) - ((int32_t)_bme280_calib.dig_T1 <<1))) * ((int32_t)_bme280_calib.dig_T2)) >> 11;
|
||||||
|
var2 = (((((adc_T>>4) - ((int32_t)_bme280_calib.dig_T1)) * ((adc_T>>4) - ((int32_t)_bme280_calib.dig_T1))) >> 12) *
|
||||||
|
((int32_t)_bme280_calib.dig_T3)) >> 14;
|
||||||
|
t_fine = var1 + var2;
|
||||||
|
double T = (t_fine * 5 + 128) >> 8;
|
||||||
|
return T / 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double bmp280_readPressure(void)
|
||||||
|
{
|
||||||
|
int64_t var1, var2, p;
|
||||||
|
|
||||||
|
// Must be done first to get the t_fine variable set up
|
||||||
|
// bmp280_readTemperature();
|
||||||
|
|
||||||
|
int32_t adc_P = i2c_read24(bmpaddr, BME280_REGISTER_PRESSUREDATA);
|
||||||
|
adc_P >>= 4;
|
||||||
|
|
||||||
|
var1 = ((int64_t)t_fine) - 128000;
|
||||||
|
var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6;
|
||||||
|
var2 = var2 + ((var1 * (int64_t)_bme280_calib.dig_P5) << 17);
|
||||||
|
var2 = var2 + (((int64_t)_bme280_calib.dig_P4) << 35);
|
||||||
|
var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) >> 8) + ((var1 * (int64_t)_bme280_calib.dig_P2) << 12);
|
||||||
|
var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)_bme280_calib.dig_P1) >> 33;
|
||||||
|
if (var1 == 0) {
|
||||||
|
return 0; // avoid exception caused by division by zero
|
||||||
|
}
|
||||||
|
p = 1048576 - adc_P;
|
||||||
|
p = (((p << 31) - var2) * 3125) / var1;
|
||||||
|
var1 = (((int64_t)_bme280_calib.dig_P9) * (p >> 13) * (p >> 13)) >> 25;
|
||||||
|
var2 = (((int64_t)_bme280_calib.dig_P8) * p) >> 19;
|
||||||
|
p = ((p + var1 + var2) >> 8) + (((int64_t)_bme280_calib.dig_P7) << 4);
|
||||||
|
return (double)p / 25600.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double bme280_readHumidity(void)
|
||||||
|
{
|
||||||
|
int32_t v_x1_u32r;
|
||||||
|
|
||||||
|
// Must be done first to get the t_fine variable set up
|
||||||
|
// bmp280_readTemperature();
|
||||||
|
|
||||||
|
int32_t adc_H = i2c_read16(bmpaddr, BME280_REGISTER_HUMIDDATA);
|
||||||
|
|
||||||
|
v_x1_u32r = (t_fine - ((int32_t)76800));
|
||||||
|
|
||||||
|
v_x1_u32r = (((((adc_H << 14) - (((int32_t)_bme280_calib.dig_H4) << 20) -
|
||||||
|
(((int32_t)_bme280_calib.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) *
|
||||||
|
(((((((v_x1_u32r * ((int32_t)_bme280_calib.dig_H6)) >> 10) *
|
||||||
|
(((v_x1_u32r * ((int32_t)_bme280_calib.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) +
|
||||||
|
((int32_t)2097152)) * ((int32_t)_bme280_calib.dig_H2) + 8192) >> 14));
|
||||||
|
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
|
||||||
|
((int32_t)_bme280_calib.dig_H1)) >> 4));
|
||||||
|
v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r;
|
||||||
|
v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r;
|
||||||
|
double h = (v_x1_u32r >> 12);
|
||||||
|
return h / 1024.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* BMP
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
double bmp_convertCtoF(double c)
|
||||||
|
{
|
||||||
|
return c * 1.8 + 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
double bmp_readTemperature(bool S)
|
||||||
|
{
|
||||||
|
double t = NAN;
|
||||||
|
|
||||||
|
switch (bmptype) {
|
||||||
|
case BMP180_CHIPID:
|
||||||
|
t = bmp180_readTemperature();
|
||||||
|
break;
|
||||||
|
case BMP280_CHIPID:
|
||||||
|
case BME280_CHIPID:
|
||||||
|
t = bmp280_readTemperature();
|
||||||
|
}
|
||||||
|
if (!isnan(t)) {
|
||||||
|
if(S) t = bmp_convertCtoF(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double bmp_readPressure(void)
|
||||||
|
{
|
||||||
|
switch (bmptype) {
|
||||||
|
case BMP180_CHIPID:
|
||||||
|
return bmp180_readPressure();
|
||||||
|
case BMP280_CHIPID:
|
||||||
|
case BME280_CHIPID:
|
||||||
|
return bmp280_readPressure();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double bmp_readHumidity(void)
|
||||||
|
{
|
||||||
|
switch (bmptype) {
|
||||||
|
case BMP180_CHIPID:
|
||||||
|
case BMP280_CHIPID:
|
||||||
|
break;
|
||||||
|
case BME280_CHIPID:
|
||||||
|
return bme280_readHumidity();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean bmp_detect()
|
||||||
|
{
|
||||||
|
if (bmptype) return true;
|
||||||
|
|
||||||
|
char log[LOGSZ];
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
bmpaddr = BMP_ADDR;
|
||||||
|
bmptype = i2c_read8(bmpaddr, BMP_REGISTER_CHIPID);
|
||||||
|
if (!bmptype) {
|
||||||
|
bmpaddr--;
|
||||||
|
bmptype = i2c_read8(bmpaddr, BMP_REGISTER_CHIPID);
|
||||||
|
}
|
||||||
|
snprintf_P(bmpstype, sizeof(bmpstype), PSTR("BMP"));
|
||||||
|
switch (bmptype) {
|
||||||
|
case BMP180_CHIPID:
|
||||||
|
success = bmp180_calibration();
|
||||||
|
snprintf_P(bmpstype, sizeof(bmpstype), PSTR("BMP180"));
|
||||||
|
break;
|
||||||
|
case BMP280_CHIPID:
|
||||||
|
success = bmp280_calibrate();
|
||||||
|
snprintf_P(bmpstype, sizeof(bmpstype), PSTR("BMP280"));
|
||||||
|
break;
|
||||||
|
case BME280_CHIPID:
|
||||||
|
success = bme280_calibrate();
|
||||||
|
snprintf_P(bmpstype, sizeof(bmpstype), PSTR("BME280"));
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("I2C: %s found at address 0x%x"), bmpstype, bmpaddr);
|
||||||
|
addLog(LOG_LEVEL_DEBUG, log);
|
||||||
|
} else {
|
||||||
|
bmptype = 0;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Presentation
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
void bmp_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx)
|
||||||
|
{
|
||||||
|
if (!bmptype) return;
|
||||||
|
|
||||||
|
char stemp1[10], stemp2[10], stemp3[10];
|
||||||
|
|
||||||
|
double t = bmp_readTemperature(TEMP_CONVERSION);
|
||||||
|
double p = bmp_readPressure();
|
||||||
|
double h = bmp_readHumidity();
|
||||||
|
dtostrf(t, 1, TEMP_RESOLUTION &3, stemp1);
|
||||||
|
dtostrf(p, 1, PRESSURE_RESOLUTION &3, stemp2);
|
||||||
|
dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp3);
|
||||||
|
if (!strcmp(bmpstype,"BME280")) {
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Temperature\":\"%s\", \"Humidity\":\"%s\", \"Pressure\":\"%s\"}"),
|
||||||
|
svalue, bmpstype, stemp1, stemp3, stemp2);
|
||||||
|
} else {
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Temperature\":\"%s\", \"Pressure\":\"%s\"}"),
|
||||||
|
svalue, bmpstype, stemp1, stemp2);
|
||||||
|
}
|
||||||
|
*djson = 1;
|
||||||
|
#ifdef USE_DOMOTICZ
|
||||||
|
domoticz_sensor3(stemp1, stemp3, stemp2);
|
||||||
|
#endif // USE_DOMOTICZ
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
String bmp_webPresent()
|
||||||
|
{
|
||||||
|
String page = "";
|
||||||
|
if (bmptype) {
|
||||||
|
char itemp[10], iconv[10];
|
||||||
|
|
||||||
|
snprintf_P(iconv, sizeof(iconv), PSTR("°%c"), (TEMP_CONVERSION) ? 'F' : 'C');
|
||||||
|
double t_bmp = bmp_readTemperature(TEMP_CONVERSION);
|
||||||
|
double p_bmp = bmp_readPressure();
|
||||||
|
double h_bmp = bmp_readHumidity();
|
||||||
|
dtostrf(t_bmp, 1, TEMP_RESOLUTION &3, itemp);
|
||||||
|
page += F("<tr><td>BMP Temperature: </td><td>"); page += itemp; page += iconv; page += F("</td></tr>");
|
||||||
|
if (!strcmp(bmpstype,"BME280")) {
|
||||||
|
dtostrf(h_bmp, 1, HUMIDITY_RESOLUTION &3, itemp);
|
||||||
|
page += F("<tr><td>BMP Humidity: </td><td>"); page += itemp; page += F("%</td></tr>");
|
||||||
|
}
|
||||||
|
dtostrf(p_bmp, 1, PRESSURE_RESOLUTION &3, itemp);
|
||||||
|
page += F("<tr><td>BMP Pressure: </td><td>"); page += itemp; page += F(" hPa</td></tr>");
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
#endif // USE_BMP
|
||||||
|
#endif // USE_I2C
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Theo Arends. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_DHT
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* DHT11, DHT21 (AM2301), DHT22 (AM2302, AM2321) - Temperature and Humidy
|
||||||
|
*
|
||||||
|
* Reading temperature or humidity takes about 250 milliseconds!
|
||||||
|
* Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
||||||
|
* Source: Adafruit Industries https://github.com/adafruit/DHT-sensor-library
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define MIN_INTERVAL 2000
|
||||||
|
|
||||||
|
uint8_t data[5];
|
||||||
|
uint32_t _lastreadtime, _maxcycles;
|
||||||
|
bool _lastresult;
|
||||||
|
float mt, mh = 0;
|
||||||
|
|
||||||
|
void dht_readPrep()
|
||||||
|
{
|
||||||
|
digitalWrite(pin[GPIO_DHT11], HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dht_expectPulse(bool level)
|
||||||
|
{
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
while (digitalRead(pin[GPIO_DHT11]) == level)
|
||||||
|
if (count++ >= _maxcycles) return 0;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean dht_read()
|
||||||
|
{
|
||||||
|
char log[LOGSZ];
|
||||||
|
uint32_t cycles[80];
|
||||||
|
uint32_t currenttime = millis();
|
||||||
|
|
||||||
|
if ((currenttime - _lastreadtime) < 2000) {
|
||||||
|
return _lastresult;
|
||||||
|
}
|
||||||
|
_lastreadtime = currenttime;
|
||||||
|
|
||||||
|
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
|
||||||
|
|
||||||
|
// digitalWrite(pin[GPIO_DHT11], HIGH);
|
||||||
|
// delay(250);
|
||||||
|
|
||||||
|
pinMode(pin[GPIO_DHT11], OUTPUT);
|
||||||
|
digitalWrite(pin[GPIO_DHT11], LOW);
|
||||||
|
delay(20);
|
||||||
|
|
||||||
|
noInterrupts();
|
||||||
|
digitalWrite(pin[GPIO_DHT11], HIGH);
|
||||||
|
delayMicroseconds(40);
|
||||||
|
pinMode(pin[GPIO_DHT11], INPUT_PULLUP);
|
||||||
|
delayMicroseconds(10);
|
||||||
|
if (dht_expectPulse(LOW) == 0) {
|
||||||
|
addLog_P(LOG_LEVEL_DEBUG, PSTR("DHT: Timeout waiting for start signal low pulse"));
|
||||||
|
_lastresult = false;
|
||||||
|
return _lastresult;
|
||||||
|
}
|
||||||
|
if (dht_expectPulse(HIGH) == 0) {
|
||||||
|
addLog_P(LOG_LEVEL_DEBUG, PSTR("DHT: Timeout waiting for start signal high pulse"));
|
||||||
|
_lastresult = false;
|
||||||
|
return _lastresult;
|
||||||
|
}
|
||||||
|
for (int i=0; i<80; i+=2) {
|
||||||
|
cycles[i] = dht_expectPulse(LOW);
|
||||||
|
cycles[i+1] = dht_expectPulse(HIGH);
|
||||||
|
}
|
||||||
|
interrupts();
|
||||||
|
|
||||||
|
for (int i=0; i<40; ++i) {
|
||||||
|
uint32_t lowCycles = cycles[2*i];
|
||||||
|
uint32_t highCycles = cycles[2*i+1];
|
||||||
|
if ((lowCycles == 0) || (highCycles == 0)) {
|
||||||
|
addLog_P(LOG_LEVEL_DEBUG, PSTR("DHT: Timeout waiting for pulse"));
|
||||||
|
_lastresult = false;
|
||||||
|
return _lastresult;
|
||||||
|
}
|
||||||
|
data[i/8] <<= 1;
|
||||||
|
if (highCycles > lowCycles) data[i/8] |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("DHT: Received %02X, %02X, %02X, %02X, %02X =? %02X"),
|
||||||
|
data[0], data[1], data[2], data[3], data[4], (data[0] + data[1] + data[2] + data[3]) & 0xFF);
|
||||||
|
addLog(LOG_LEVEL_DEBUG, log);
|
||||||
|
|
||||||
|
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
|
||||||
|
_lastresult = true;
|
||||||
|
return _lastresult;
|
||||||
|
} else {
|
||||||
|
addLog_P(LOG_LEVEL_DEBUG, PSTR("DHT: Checksum failure"));
|
||||||
|
_lastresult = false;
|
||||||
|
return _lastresult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float dht_convertCtoF(float c)
|
||||||
|
{
|
||||||
|
return c * 1.8 + 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean dht_readTempHum(bool S, float &t, float &h)
|
||||||
|
{
|
||||||
|
if (!mh) {
|
||||||
|
t = NAN;
|
||||||
|
h = NAN;
|
||||||
|
} else {
|
||||||
|
t = mt;
|
||||||
|
h = mh;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dht_read()) {
|
||||||
|
switch (dht_type) {
|
||||||
|
case DHT11:
|
||||||
|
h = data[0];
|
||||||
|
t = data[2];
|
||||||
|
if(S) t = dht_convertCtoF(t);
|
||||||
|
break;
|
||||||
|
case DHT22:
|
||||||
|
case DHT21:
|
||||||
|
h = data[0];
|
||||||
|
h *= 256;
|
||||||
|
h += data[1];
|
||||||
|
h *= 0.1;
|
||||||
|
t = data[2] & 0x7F;
|
||||||
|
t *= 256;
|
||||||
|
t += data[3];
|
||||||
|
t *= 0.1;
|
||||||
|
if (data[2] & 0x80) t *= -1;
|
||||||
|
if(S) t = dht_convertCtoF(t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!isnan(t)) mt = t;
|
||||||
|
if (!isnan(h)) mh = h;
|
||||||
|
}
|
||||||
|
return (!isnan(t) && !isnan(h));
|
||||||
|
}
|
||||||
|
|
||||||
|
void dht_init()
|
||||||
|
{
|
||||||
|
char log[LOGSZ];
|
||||||
|
_maxcycles = microsecondsToClockCycles(1000); // 1 millisecond timeout for
|
||||||
|
// reading pulses from DHT sensor.
|
||||||
|
pinMode(pin[GPIO_DHT11], INPUT_PULLUP);
|
||||||
|
_lastreadtime = -MIN_INTERVAL;
|
||||||
|
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("DHT: Max clock cycles %d"), _maxcycles);
|
||||||
|
addLog(LOG_LEVEL_DEBUG, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Presentation
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
void dht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx)
|
||||||
|
{
|
||||||
|
char stemp1[10], stemp2[10];
|
||||||
|
float t, h;
|
||||||
|
|
||||||
|
if (dht_readTempHum(TEMP_CONVERSION, t, h)) { // Read temperature
|
||||||
|
dtostrf(t, 1, TEMP_RESOLUTION &3, stemp1);
|
||||||
|
dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp2);
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("%s, \"DHT\":{\"Temperature\":\"%s\", \"Humidity\":\"%s\"}"), svalue, stemp1, stemp2);
|
||||||
|
*djson = 1;
|
||||||
|
#ifdef USE_DOMOTICZ
|
||||||
|
domoticz_sensor2(stemp1, stemp2);
|
||||||
|
#endif // USE_DOMOTICZ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
String dht_webPresent()
|
||||||
|
{
|
||||||
|
char stemp[10], sconv[10];
|
||||||
|
float t, h;
|
||||||
|
String page = "";
|
||||||
|
|
||||||
|
if (dht_readTempHum(TEMP_CONVERSION, t, h)) { // Read temperature as Celsius (the default)
|
||||||
|
snprintf_P(sconv, sizeof(sconv), PSTR("°%c"), (TEMP_CONVERSION) ? 'F' : 'C');
|
||||||
|
dtostrf(t, 1, TEMP_RESOLUTION &3, stemp);
|
||||||
|
page += F("<tr><td>DHT Temperature: </td><td>"); page += stemp; page += sconv; page += F("</td></tr>");
|
||||||
|
dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp);
|
||||||
|
page += F("<tr><td>DHT Humidity: </td><td>"); page += stemp; page += F("%</td></tr>");
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
#endif // USE_DHT
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Theo Arends. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_DHT2
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* DHT11, DHT21 (AM2301), DHT22 (AM2302, AM2321) - Temperature and Humidy
|
||||||
|
*
|
||||||
|
* Reading temperature or humidity takes about 250 milliseconds!
|
||||||
|
* Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
// WARNING: To use this DHT library you'll need to delete files DHT_U.cpp and DHT_U.h if present
|
||||||
|
|
||||||
|
#include "DHT.h"
|
||||||
|
|
||||||
|
DHT dht2(pin[GPIO_DHT11], dht_type);
|
||||||
|
|
||||||
|
float dht2_t, dht2_h = 0;
|
||||||
|
|
||||||
|
boolean dht_readTempHum(bool S, float &t, float &h)
|
||||||
|
{
|
||||||
|
h = dht2.readHumidity();
|
||||||
|
t = dht2.readTemperature(S);
|
||||||
|
if (!isnan(t)) dht2_t = t; else if (dht2_h) t = dht2_t;
|
||||||
|
if (!isnan(h)) dht2_h = h; else if (dht2_h) h = dht2_h;
|
||||||
|
return (!isnan(t) && !isnan(h));
|
||||||
|
}
|
||||||
|
|
||||||
|
void dht_init()
|
||||||
|
{
|
||||||
|
dht2.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Presentation
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
void dht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx)
|
||||||
|
{
|
||||||
|
char stemp1[10], stemp2[10];
|
||||||
|
float t, h;
|
||||||
|
|
||||||
|
if (dht_readTempHum(TEMP_CONVERSION, t, h)) { // Read temperature
|
||||||
|
dtostrf(t, 1, TEMP_RESOLUTION &3, stemp1);
|
||||||
|
dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp2);
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("%s, \"DHT\":{\"Temperature\":\"%s\", \"Humidity\":\"%s\"}"), svalue, stemp1, stemp2);
|
||||||
|
*djson = 1;
|
||||||
|
#ifdef USE_DOMOTICZ
|
||||||
|
domoticz_sensor2(stemp1, stemp2);
|
||||||
|
#endif // USE_DOMOTICZ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
String dht_webPresent()
|
||||||
|
{
|
||||||
|
char stemp[10], sconv[10];
|
||||||
|
float t, h;
|
||||||
|
String page = "";
|
||||||
|
|
||||||
|
if (dht_readTempHum(TEMP_CONVERSION, t, h)) { // Read temperature as Celsius (the default)
|
||||||
|
snprintf_P(sconv, sizeof(sconv), PSTR("°%c"), (TEMP_CONVERSION) ? 'F' : 'C');
|
||||||
|
dtostrf(t, 1, TEMP_RESOLUTION &3, stemp);
|
||||||
|
page += F("<tr><td>DHT Temperature: </td><td>"); page += stemp; page += sconv; page += F("</td></tr>");
|
||||||
|
dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp);
|
||||||
|
page += F("<tr><td>DHT Humidity: </td><td>"); page += stemp; page += F("%</td></tr>");
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
#endif // USE_DHT2
|
|
@ -0,0 +1,206 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Theo Arends. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_DS18B20
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* DS18B20 - Temperature
|
||||||
|
*
|
||||||
|
* Source: Marinus vd Broek https://github.com/ESP8266nu/ESPEasy and AlexTransit (CRC)
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
uint8_t dsb_reset()
|
||||||
|
{
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t retries = 125;
|
||||||
|
|
||||||
|
pinMode(pin[GPIO_DSB], INPUT);
|
||||||
|
do { // wait until the wire is high... just in case
|
||||||
|
if (--retries == 0) return 0;
|
||||||
|
delayMicroseconds(2);
|
||||||
|
} while (!digitalRead(pin[GPIO_DSB]));
|
||||||
|
pinMode(pin[GPIO_DSB], OUTPUT);
|
||||||
|
digitalWrite(pin[GPIO_DSB], LOW);
|
||||||
|
delayMicroseconds(492); // Dallas spec. = Min. 480uSec. Arduino 500uSec.
|
||||||
|
pinMode(pin[GPIO_DSB], INPUT); // Float
|
||||||
|
delayMicroseconds(40);
|
||||||
|
r = !digitalRead(pin[GPIO_DSB]);
|
||||||
|
delayMicroseconds(420);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dsb_read_bit(void)
|
||||||
|
{
|
||||||
|
uint8_t r;
|
||||||
|
|
||||||
|
pinMode(pin[GPIO_DSB], OUTPUT);
|
||||||
|
digitalWrite(pin[GPIO_DSB], LOW);
|
||||||
|
delayMicroseconds(3);
|
||||||
|
pinMode(pin[GPIO_DSB], INPUT); // let pin float, pull up will raise
|
||||||
|
delayMicroseconds(10);
|
||||||
|
r = digitalRead(pin[GPIO_DSB]);
|
||||||
|
delayMicroseconds(53);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dsb_read(void)
|
||||||
|
{
|
||||||
|
uint8_t bitMask;
|
||||||
|
uint8_t r = 0;
|
||||||
|
|
||||||
|
for (bitMask = 0x01; bitMask; bitMask <<= 1)
|
||||||
|
if (dsb_read_bit()) r |= bitMask;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsb_write_bit(uint8_t v)
|
||||||
|
{
|
||||||
|
if (v & 1) {
|
||||||
|
digitalWrite(pin[GPIO_DSB], LOW);
|
||||||
|
pinMode(pin[GPIO_DSB], OUTPUT);
|
||||||
|
delayMicroseconds(10);
|
||||||
|
digitalWrite(pin[GPIO_DSB], HIGH);
|
||||||
|
delayMicroseconds(55);
|
||||||
|
} else {
|
||||||
|
digitalWrite(pin[GPIO_DSB], LOW);
|
||||||
|
pinMode(pin[GPIO_DSB], OUTPUT);
|
||||||
|
delayMicroseconds(65);
|
||||||
|
digitalWrite(pin[GPIO_DSB], HIGH);
|
||||||
|
delayMicroseconds(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsb_write(uint8_t ByteToWrite)
|
||||||
|
{
|
||||||
|
uint8_t bitMask;
|
||||||
|
|
||||||
|
for (bitMask = 0x01; bitMask; bitMask <<= 1)
|
||||||
|
dsb_write_bit((bitMask & ByteToWrite) ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 dsb_crc(uint8 inp, uint8 crc)
|
||||||
|
{
|
||||||
|
inp ^= crc;
|
||||||
|
crc = 0;
|
||||||
|
if (inp & 0x1) crc ^= 0x5e;
|
||||||
|
if (inp & 0x2) crc ^= 0xbc;
|
||||||
|
if (inp & 0x4) crc ^= 0x61;
|
||||||
|
if (inp & 0x8) crc ^= 0xc2;
|
||||||
|
if (inp & 0x10) crc ^= 0x9d;
|
||||||
|
if (inp & 0x20) crc ^= 0x23;
|
||||||
|
if (inp & 0x40) crc ^= 0x46;
|
||||||
|
if (inp & 0x80) crc ^= 0x8c;
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsb_readTempPrep()
|
||||||
|
{
|
||||||
|
dsb_reset();
|
||||||
|
dsb_write(0xCC); // Skip ROM
|
||||||
|
dsb_write(0x44); // Start conversion
|
||||||
|
}
|
||||||
|
|
||||||
|
float dsb_convertCtoF(float c)
|
||||||
|
{
|
||||||
|
return c * 1.8 + 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean dsb_readTemp(bool S, float &t)
|
||||||
|
{
|
||||||
|
int16_t DSTemp;
|
||||||
|
byte msb, lsb, crc;
|
||||||
|
|
||||||
|
t = NAN;
|
||||||
|
|
||||||
|
if (!dsb_read_bit()) { //check measurement end
|
||||||
|
addLog_P(LOG_LEVEL_DEBUG, PSTR("DSB: Sensor busy"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
dsb_reset();
|
||||||
|
dsb_write(0xCC); // Skip ROM
|
||||||
|
dsb_write(0x44); // Start conversion
|
||||||
|
delay(800);
|
||||||
|
*/
|
||||||
|
dsb_reset();
|
||||||
|
dsb_write(0xCC); // Skip ROM
|
||||||
|
dsb_write(0xBE); // Read scratchpad
|
||||||
|
lsb = dsb_read();
|
||||||
|
msb = dsb_read();
|
||||||
|
crc = dsb_crc(lsb, crc);
|
||||||
|
crc = dsb_crc(msb, crc);
|
||||||
|
crc = dsb_crc(dsb_read(), crc);
|
||||||
|
crc = dsb_crc(dsb_read(), crc);
|
||||||
|
crc = dsb_crc(dsb_read(), crc);
|
||||||
|
crc = dsb_crc(dsb_read(), crc);
|
||||||
|
crc = dsb_crc(dsb_read(), crc);
|
||||||
|
crc = dsb_crc(dsb_read(), crc);
|
||||||
|
crc = dsb_crc(dsb_read(), crc);
|
||||||
|
dsb_reset();
|
||||||
|
if (crc) { //check crc
|
||||||
|
addLog_P(LOG_LEVEL_DEBUG, PSTR("DSB: Sensor CRC error"));
|
||||||
|
} else {
|
||||||
|
DSTemp = (msb << 8) + lsb;
|
||||||
|
t = (float(DSTemp) * 0.0625);
|
||||||
|
if(S) t = dsb_convertCtoF(t);
|
||||||
|
}
|
||||||
|
return !isnan(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Presentation
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
void dsb_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx)
|
||||||
|
{
|
||||||
|
char stemp1[10];
|
||||||
|
float t;
|
||||||
|
|
||||||
|
if (dsb_readTemp(TEMP_CONVERSION, t)) { // Check if read failed
|
||||||
|
dtostrf(t, 1, TEMP_RESOLUTION &3, stemp1);
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("%s, \"DS18B20\":{\"Temperature\":\"%s\"}"), svalue, stemp1);
|
||||||
|
*djson = 1;
|
||||||
|
#ifdef USE_DOMOTICZ
|
||||||
|
domoticz_sensor1(stemp1);
|
||||||
|
#endif // USE_DOMOTICZ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
String dsb_webPresent()
|
||||||
|
{
|
||||||
|
// Needs TelePeriod to refresh data (Do not do it here as it takes too much time)
|
||||||
|
char stemp[10], sconv[10];
|
||||||
|
float st;
|
||||||
|
String page = "";
|
||||||
|
|
||||||
|
if (dsb_readTemp(TEMP_CONVERSION, st)) { // Check if read failed
|
||||||
|
snprintf_P(sconv, sizeof(sconv), PSTR("°%c"), (TEMP_CONVERSION) ? 'F' : 'C');
|
||||||
|
dtostrf(st, 1, TEMP_RESOLUTION &3, stemp);
|
||||||
|
page += F("<tr><td>DSB Temperature: </td><td>"); page += stemp; page += sconv; page += F("</td></tr>");
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
#endif // USE_DS18B20
|
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Theo Arends. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_DS18x20
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* DS18B20 - Temperature
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define W1_SKIP_ROM 0xCC
|
||||||
|
#define W1_CONVERT_TEMP 0x44
|
||||||
|
#define W1_READ_SCRATCHPAD 0xBE
|
||||||
|
|
||||||
|
#define DS18X20_MAX_SENSORS 8
|
||||||
|
|
||||||
|
#include <OneWire.h>
|
||||||
|
|
||||||
|
OneWire ds(pin[GPIO_DSB]);
|
||||||
|
|
||||||
|
uint8_t ds18x20_addr[DS18X20_MAX_SENSORS][8];
|
||||||
|
uint8_t ds18x20_idx[DS18X20_MAX_SENSORS];
|
||||||
|
uint8_t ds18x20_snsrs = 0;
|
||||||
|
|
||||||
|
void ds18x20_search()
|
||||||
|
{
|
||||||
|
uint8_t num_sensors=0;
|
||||||
|
uint8_t sensor = 0;
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
ds.reset_search();
|
||||||
|
for (num_sensors = 0; num_sensors < DS18X20_MAX_SENSORS; num_sensors)
|
||||||
|
{
|
||||||
|
if (!ds.search(ds18x20_addr[num_sensors])) {
|
||||||
|
ds.reset_search();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If CRC Ok and Type DS18S20 or DS18B20
|
||||||
|
if ((OneWire::crc8(ds18x20_addr[num_sensors], 7) == ds18x20_addr[num_sensors][7]) &&
|
||||||
|
((ds18x20_addr[num_sensors][0]==0x10) || (ds18x20_addr[num_sensors][0]==0x28)))
|
||||||
|
num_sensors++;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < num_sensors; i++) ds18x20_idx[i] = i;
|
||||||
|
for (int i = 0; i < num_sensors; i++) {
|
||||||
|
for (int j = i + 1; j < num_sensors; j++) {
|
||||||
|
if (uint32_t(ds18x20_addr[ds18x20_idx[i]]) > uint32_t(ds18x20_addr[ds18x20_idx[j]])) {
|
||||||
|
std::swap(ds18x20_idx[i], ds18x20_idx[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ds18x20_snsrs = num_sensors;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ds18x20_sensors()
|
||||||
|
{
|
||||||
|
return ds18x20_snsrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ds18x20_address(uint8_t sensor)
|
||||||
|
{
|
||||||
|
char addrStr[20];
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) sprintf(addrStr+2*i, "%02X", ds18x20_addr[ds18x20_idx[sensor]][i]);
|
||||||
|
return String(addrStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
String ds18x20_type(uint8_t sensor)
|
||||||
|
{
|
||||||
|
char typeStr[10];
|
||||||
|
|
||||||
|
switch(ds18x20_addr[ds18x20_idx[sensor]][0]) {
|
||||||
|
case 0x10:
|
||||||
|
strcpy(typeStr, "DS18S20");
|
||||||
|
break;
|
||||||
|
case 0x28:
|
||||||
|
strcpy(typeStr, "DS18B20");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strcpy(typeStr, "DS18x20");
|
||||||
|
}
|
||||||
|
return String(typeStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ds18x20_convert()
|
||||||
|
{
|
||||||
|
ds.reset();
|
||||||
|
ds.write(W1_SKIP_ROM); // Address all Sensors on Bus
|
||||||
|
ds.write(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end
|
||||||
|
// delay(750); // 750ms should be enough for 12bit conv
|
||||||
|
}
|
||||||
|
|
||||||
|
float ds18x20_convertCtoF(float c)
|
||||||
|
{
|
||||||
|
return c * 1.8 + 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean ds18x20_read(uint8_t sensor, bool S, float &t)
|
||||||
|
{
|
||||||
|
byte data[12];
|
||||||
|
uint8_t sign = 1;
|
||||||
|
uint8_t i = 0;
|
||||||
|
float temp9 = 0.0;
|
||||||
|
uint8_t present = 0;
|
||||||
|
|
||||||
|
t = NAN;
|
||||||
|
|
||||||
|
ds.reset();
|
||||||
|
ds.select(ds18x20_addr[ds18x20_idx[sensor]]);
|
||||||
|
ds.write(W1_READ_SCRATCHPAD); // Read Scratchpad
|
||||||
|
|
||||||
|
for (i = 0; i < 9; i++) data[i] = ds.read();
|
||||||
|
if (OneWire::crc8(data, 8) == data[8]) {
|
||||||
|
switch(ds18x20_addr[ds18x20_idx[sensor]][0]) {
|
||||||
|
case 0x10: // DS18S20
|
||||||
|
if (data[1] > 0x80) sign = -1; // App-Note fix possible sign error
|
||||||
|
if (data[0] & 1) {
|
||||||
|
temp9 = ((data[0] >> 1) + 0.5) * sign;
|
||||||
|
} else {
|
||||||
|
temp9 = (data[0] >> 1) * sign;
|
||||||
|
}
|
||||||
|
t = (temp9 - 0.25) + ((16.0 - data[6]) / 16.0);
|
||||||
|
if(S) t = ds18x20_convertCtoF(t);
|
||||||
|
break;
|
||||||
|
case 0x28: // DS18B20
|
||||||
|
t = ((data[1] << 8) + data[0]) * 0.0625;
|
||||||
|
if(S) t = ds18x20_convertCtoF(t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (!isnan(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Presentation
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
void ds18x20_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx)
|
||||||
|
{
|
||||||
|
char stemp1[10], stemp2[10];
|
||||||
|
float t;
|
||||||
|
|
||||||
|
byte dsxflg = 0;
|
||||||
|
for (byte i = 0; i < ds18x20_sensors(); i++) {
|
||||||
|
if (ds18x20_read(i, TEMP_CONVERSION, t)) { // Check if read failed
|
||||||
|
dtostrf(t, 1, TEMP_RESOLUTION &3, stemp2);
|
||||||
|
if (!dsxflg) {
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("%s, \"DS18x20\":{"), svalue);
|
||||||
|
*djson = 1;
|
||||||
|
stemp1[0] = '\0';
|
||||||
|
}
|
||||||
|
dsxflg++;
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("%s%s\"DS%d\":{\"Type\":\"%s\", \"Address\":\"%s\", \"Temperature\":\"%s\"}"),
|
||||||
|
svalue, stemp1, i +1, ds18x20_type(i).c_str(), ds18x20_address(i).c_str(), stemp2);
|
||||||
|
strcpy(stemp1, ", ");
|
||||||
|
#ifdef USE_DOMOTICZ
|
||||||
|
if (dsxflg == 1) domoticz_sensor1(stemp2);
|
||||||
|
#endif // USE_DOMOTICZ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dsxflg) snprintf_P(svalue, ssvalue, PSTR("%s}"), svalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
String ds18x20_webPresent()
|
||||||
|
{
|
||||||
|
char stemp[10], sconv[10];
|
||||||
|
float t;
|
||||||
|
String page = "";
|
||||||
|
|
||||||
|
snprintf_P(sconv, sizeof(sconv), PSTR("°%c"), (TEMP_CONVERSION) ? 'F' : 'C');
|
||||||
|
for (byte i = 0; i < ds18x20_sensors(); i++) {
|
||||||
|
if (ds18x20_read(i, TEMP_CONVERSION, t)) { // Check if read failed
|
||||||
|
dtostrf(t, 1, TEMP_RESOLUTION &3, stemp);
|
||||||
|
page += F("<tr><td>DS"); page += String(i +1); page += F(" Temperature: </td><td>"); page += stemp; page += sconv; page += F("</td></tr>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
#endif // USE_DS18x20
|
|
@ -0,0 +1,412 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Theo Arends. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* HLW8012 - Energy
|
||||||
|
*
|
||||||
|
* Based on Source: Shenzhen Heli Technology Co., Ltd
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define HLW_PREF 10000 // 1000.0W
|
||||||
|
#define HLW_UREF 2200 // 220.0V
|
||||||
|
#define HLW_IREF 4545 // 4.545A
|
||||||
|
|
||||||
|
byte hlw_SELflag, hlw_cf_timer, hlw_cf1_timer, hlw_fifth_second, hlw_startup;
|
||||||
|
unsigned long hlw_cf_plen, hlw_cf_last;
|
||||||
|
unsigned long hlw_cf1_plen, hlw_cf1_last, hlw_cf1_ptot, hlw_cf1_pcnt, hlw_cf1u_plen, hlw_cf1i_plen;
|
||||||
|
unsigned long hlw_Ecntr, hlw_EDcntr, hlw_kWhtoday;
|
||||||
|
uint32_t hlw_lasttime;
|
||||||
|
|
||||||
|
unsigned long hlw_cf1u_pcntmax, hlw_cf1i_pcntmax;
|
||||||
|
|
||||||
|
Ticker tickerHLW;
|
||||||
|
|
||||||
|
#ifndef USE_WS2812_DMA // Collides with Neopixelbus but solves exception
|
||||||
|
void hlw_cf_interrupt() ICACHE_RAM_ATTR;
|
||||||
|
void hlw_cf1_interrupt() ICACHE_RAM_ATTR;
|
||||||
|
#endif // USE_WS2812_DMA
|
||||||
|
|
||||||
|
void hlw_cf_interrupt() // Service Power
|
||||||
|
{
|
||||||
|
hlw_cf_plen = micros() - hlw_cf_last;
|
||||||
|
hlw_cf_last = micros();
|
||||||
|
if (hlw_cf_plen > 4000000) hlw_cf_plen = 0; // Just powered on
|
||||||
|
hlw_cf_timer = 15; // Support down to 4W which takes about 3 seconds
|
||||||
|
hlw_EDcntr++;
|
||||||
|
hlw_Ecntr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hlw_cf1_interrupt() // Service Voltage and Current
|
||||||
|
{
|
||||||
|
hlw_cf1_plen = micros() - hlw_cf1_last;
|
||||||
|
hlw_cf1_last = micros();
|
||||||
|
if ((hlw_cf1_timer > 2) && (hlw_cf1_timer < 8)) { // Allow for 300 mSec set-up time and measure for up to 1 second
|
||||||
|
hlw_cf1_ptot += hlw_cf1_plen;
|
||||||
|
hlw_cf1_pcnt++;
|
||||||
|
if (hlw_cf1_pcnt == 10) hlw_cf1_timer = 8; // We need up to ten samples within 1 second (low current could take up to 0.3 second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hlw_200mS()
|
||||||
|
{
|
||||||
|
unsigned long hlw_len, hlw_temp;
|
||||||
|
|
||||||
|
hlw_fifth_second++;
|
||||||
|
if (hlw_fifth_second == 5) {
|
||||||
|
hlw_fifth_second = 0;
|
||||||
|
|
||||||
|
if (hlw_EDcntr) {
|
||||||
|
hlw_len = 1000000 / hlw_EDcntr;
|
||||||
|
hlw_EDcntr = 0;
|
||||||
|
hlw_temp = (HLW_PREF * sysCfg.hlw_pcal) / hlw_len;
|
||||||
|
hlw_kWhtoday += (hlw_temp * 100) / 36;
|
||||||
|
}
|
||||||
|
if (rtc_loctime() == rtc_midnight()) {
|
||||||
|
sysCfg.hlw_kWhyesterday = hlw_kWhtoday;
|
||||||
|
hlw_kWhtoday = 0;
|
||||||
|
}
|
||||||
|
if (hlw_startup && rtcTime.Valid && (rtcTime.DayOfYear == sysCfg.hlw_kWhdoy)) {
|
||||||
|
hlw_kWhtoday = sysCfg.hlw_kWhtoday;
|
||||||
|
hlw_startup = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hlw_cf_timer) {
|
||||||
|
hlw_cf_timer--;
|
||||||
|
if (!hlw_cf_timer) hlw_cf_plen = 0; // No load for over three seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
hlw_cf1_timer++;
|
||||||
|
if (hlw_cf1_timer >= 8) {
|
||||||
|
hlw_cf1_timer = 0;
|
||||||
|
hlw_SELflag = (hlw_SELflag) ? 0 : 1;
|
||||||
|
digitalWrite(pin[GPIO_HLW_SEL], hlw_SELflag);
|
||||||
|
|
||||||
|
if (hlw_cf1_pcnt) {
|
||||||
|
hlw_cf1_plen = hlw_cf1_ptot / hlw_cf1_pcnt;
|
||||||
|
} else {
|
||||||
|
hlw_cf1_plen = 0;
|
||||||
|
}
|
||||||
|
if (hlw_SELflag) {
|
||||||
|
hlw_cf1u_plen = hlw_cf1_plen;
|
||||||
|
hlw_cf1u_pcntmax = hlw_cf1_pcnt;
|
||||||
|
} else {
|
||||||
|
hlw_cf1i_plen = hlw_cf1_plen;
|
||||||
|
hlw_cf1i_pcntmax = hlw_cf1_pcnt;
|
||||||
|
}
|
||||||
|
hlw_cf1_ptot = 0;
|
||||||
|
hlw_cf1_pcnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hlw_savestate()
|
||||||
|
{
|
||||||
|
sysCfg.hlw_kWhdoy = (rtcTime.Valid) ? rtcTime.DayOfYear : 0;
|
||||||
|
sysCfg.hlw_kWhtoday = hlw_kWhtoday;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hlw_readEnergy(byte option, float &ed, uint16_t &e, uint16_t &w, uint16_t &u, float &i, float &c)
|
||||||
|
{
|
||||||
|
unsigned long hlw_len, hlw_temp, hlw_w, hlw_u, hlw_i;
|
||||||
|
int hlw_period, hlw_interval;
|
||||||
|
|
||||||
|
//char log[LOGSZ];
|
||||||
|
//snprintf_P(log, sizeof(log), PSTR("HLW: CF %d, CF1U %d (%d), CF1I %d (%d)"), hlw_cf_plen, hlw_cf1u_plen, hlw_cf1u_pcntmax, hlw_cf1i_plen, hlw_cf1i_pcntmax);
|
||||||
|
//addLog(LOG_LEVEL_DEBUG, log);
|
||||||
|
|
||||||
|
if (hlw_kWhtoday) {
|
||||||
|
ed = (float)hlw_kWhtoday / 100000000;
|
||||||
|
} else {
|
||||||
|
ed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option) {
|
||||||
|
if (!hlw_lasttime) {
|
||||||
|
hlw_period = sysCfg.tele_period;
|
||||||
|
} else {
|
||||||
|
hlw_period = rtc_loctime() - hlw_lasttime;
|
||||||
|
}
|
||||||
|
hlw_lasttime = rtc_loctime();
|
||||||
|
hlw_interval = 3600 / hlw_period;
|
||||||
|
if (hlw_Ecntr) {
|
||||||
|
hlw_len = hlw_period * 1000000 / hlw_Ecntr;
|
||||||
|
hlw_Ecntr = 0;
|
||||||
|
hlw_temp = ((HLW_PREF * sysCfg.hlw_pcal) / hlw_len) / hlw_interval;
|
||||||
|
e = hlw_temp / 10;
|
||||||
|
} else {
|
||||||
|
e = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hlw_cf_plen) {
|
||||||
|
hlw_w = (HLW_PREF * sysCfg.hlw_pcal) / hlw_cf_plen;
|
||||||
|
w = hlw_w / 10;
|
||||||
|
} else {
|
||||||
|
w = 0;
|
||||||
|
}
|
||||||
|
if (hlw_cf1u_plen && (w || (power &1))) {
|
||||||
|
hlw_u = (HLW_UREF * sysCfg.hlw_ucal) / hlw_cf1u_plen;
|
||||||
|
u = hlw_u / 10;
|
||||||
|
} else {
|
||||||
|
u = 0;
|
||||||
|
}
|
||||||
|
if (hlw_cf1i_plen && w) {
|
||||||
|
hlw_i = (HLW_IREF * sysCfg.hlw_ical) / hlw_cf1i_plen;
|
||||||
|
i = (float)hlw_i / 1000;
|
||||||
|
} else {
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
if (hlw_i && hlw_u && hlw_w && w) {
|
||||||
|
hlw_temp = (hlw_w * 100) / ((hlw_u * hlw_i) / 1000);
|
||||||
|
if (hlw_temp > 100) {
|
||||||
|
hlw_temp = 100;
|
||||||
|
}
|
||||||
|
c = (float)hlw_temp / 100;
|
||||||
|
} else {
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hlw_init()
|
||||||
|
{
|
||||||
|
if (!sysCfg.hlw_pcal || (sysCfg.hlw_pcal == 4975)) {
|
||||||
|
sysCfg.hlw_pcal = HLW_PREF_PULSE;
|
||||||
|
sysCfg.hlw_ucal = HLW_UREF_PULSE;
|
||||||
|
sysCfg.hlw_ical = HLW_IREF_PULSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
hlw_cf_plen = 0;
|
||||||
|
hlw_cf_last = 0;
|
||||||
|
hlw_cf1_plen = 0;
|
||||||
|
hlw_cf1_last = 0;
|
||||||
|
hlw_cf1u_plen = 0;
|
||||||
|
hlw_cf1i_plen = 0;
|
||||||
|
hlw_cf1u_pcntmax = 0;
|
||||||
|
hlw_cf1i_pcntmax = 0;
|
||||||
|
|
||||||
|
hlw_Ecntr = 0;
|
||||||
|
hlw_EDcntr = 0;
|
||||||
|
hlw_kWhtoday = 0;
|
||||||
|
|
||||||
|
hlw_SELflag = 0; // Voltage;
|
||||||
|
|
||||||
|
pinMode(pin[GPIO_HLW_SEL], OUTPUT);
|
||||||
|
digitalWrite(pin[GPIO_HLW_SEL], hlw_SELflag);
|
||||||
|
pinMode(pin[GPIO_HLW_CF1], INPUT_PULLUP);
|
||||||
|
attachInterrupt(pin[GPIO_HLW_CF1], hlw_cf1_interrupt, FALLING);
|
||||||
|
pinMode(pin[GPIO_HLW_CF], INPUT_PULLUP);
|
||||||
|
attachInterrupt(pin[GPIO_HLW_CF], hlw_cf_interrupt, FALLING);
|
||||||
|
|
||||||
|
hlw_startup = 1;
|
||||||
|
hlw_lasttime = 0;
|
||||||
|
hlw_fifth_second = 0;
|
||||||
|
hlw_cf_timer = 0;
|
||||||
|
hlw_cf1_timer = 0;
|
||||||
|
tickerHLW.attach_ms(200, hlw_200mS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************/
|
||||||
|
|
||||||
|
boolean hlw_margin(byte type, uint16_t margin, uint16_t value, byte &flag, byte &saveflag)
|
||||||
|
{
|
||||||
|
byte change;
|
||||||
|
|
||||||
|
if (!margin) return false;
|
||||||
|
change = saveflag;
|
||||||
|
if (type) {
|
||||||
|
flag = (value > margin);
|
||||||
|
} else {
|
||||||
|
flag = (value < margin);
|
||||||
|
}
|
||||||
|
saveflag = flag;
|
||||||
|
return (change != saveflag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hlw_margin_chk()
|
||||||
|
{
|
||||||
|
char log[LOGSZ], stopic[TOPSZ], svalue[MESSZ];
|
||||||
|
float ped, pi, pc;
|
||||||
|
uint16_t uped, piv, pe, pw, pu;
|
||||||
|
byte flag, jsonflg;
|
||||||
|
|
||||||
|
if (power_steady_cntr) {
|
||||||
|
power_steady_cntr--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hlw_readEnergy(0, ped, pe, pw, pu, pi, pc);
|
||||||
|
if (power && (sysCfg.hlw_pmin || sysCfg.hlw_pmax || sysCfg.hlw_umin || sysCfg.hlw_umax || sysCfg.hlw_imin || sysCfg.hlw_imax)) {
|
||||||
|
piv = (uint16_t)(pi * 1000);
|
||||||
|
|
||||||
|
// snprintf_P(log, sizeof(log), PSTR("HLW: W %d, U %d, I %d"), pw, pu, piv);
|
||||||
|
// addLog(LOG_LEVEL_DEBUG, log);
|
||||||
|
|
||||||
|
snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/TELEMETRY"), PUB_PREFIX2, sysCfg.mqtt_topic);
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("{"));
|
||||||
|
jsonflg = 0;
|
||||||
|
if (hlw_margin(0, sysCfg.hlw_pmin, pw, flag, hlw_pminflg)) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"PowerLow\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
|
||||||
|
jsonflg = 1;
|
||||||
|
}
|
||||||
|
if (hlw_margin(1, sysCfg.hlw_pmax, pw, flag, hlw_pmaxflg)) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"PowerHigh\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
|
||||||
|
jsonflg = 1;
|
||||||
|
}
|
||||||
|
if (hlw_margin(0, sysCfg.hlw_umin, pu, flag, hlw_uminflg)) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"VoltageLow\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
|
||||||
|
jsonflg = 1;
|
||||||
|
}
|
||||||
|
if (hlw_margin(1, sysCfg.hlw_umax, pw, flag, hlw_umaxflg)) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"VoltageHigh\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
|
||||||
|
jsonflg = 1;
|
||||||
|
}
|
||||||
|
if (hlw_margin(0, sysCfg.hlw_imin, piv, flag, hlw_iminflg)) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"CurrentLow\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
|
||||||
|
jsonflg = 1;
|
||||||
|
}
|
||||||
|
if (hlw_margin(1, sysCfg.hlw_imax, piv, flag, hlw_imaxflg)) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"CurrentHigh\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
|
||||||
|
jsonflg = 1;
|
||||||
|
}
|
||||||
|
if (jsonflg) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("%s}"), svalue);
|
||||||
|
mqtt_publish(stopic, svalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FEATURE_POWER_LIMIT
|
||||||
|
snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/RESULT"), PUB_PREFIX, sysCfg.mqtt_topic);
|
||||||
|
// Max Power
|
||||||
|
if (sysCfg.hlw_mpl) {
|
||||||
|
if (pw > sysCfg.hlw_mpl) {
|
||||||
|
if (!hlw_mplh_counter) {
|
||||||
|
hlw_mplh_counter = sysCfg.hlw_mplh;
|
||||||
|
} else {
|
||||||
|
hlw_mplh_counter--;
|
||||||
|
if (!hlw_mplh_counter) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("{\"MaxPowerReached\":\"%d%s\"}"), pw, (sysCfg.value_units) ? " W" : "");
|
||||||
|
mqtt_publish(stopic, svalue);
|
||||||
|
do_cmnd_power(1, 0);
|
||||||
|
if (!hlw_mplr_counter) hlw_mplr_counter = MAX_POWER_RETRY +1;
|
||||||
|
hlw_mplw_counter = sysCfg.hlw_mplw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (power && (pw <= sysCfg.hlw_mpl)) {
|
||||||
|
hlw_mplh_counter = 0;
|
||||||
|
hlw_mplr_counter = 0;
|
||||||
|
hlw_mplw_counter = 0;
|
||||||
|
}
|
||||||
|
if (!power) {
|
||||||
|
if (hlw_mplw_counter) {
|
||||||
|
hlw_mplw_counter--;
|
||||||
|
} else {
|
||||||
|
if (hlw_mplr_counter) {
|
||||||
|
hlw_mplr_counter--;
|
||||||
|
if (hlw_mplr_counter) {
|
||||||
|
snprintf_P(svalue, sizeof(stopic), PSTR("{\"PowerMonitor\":\"%s\"}"), MQTT_STATUS_ON);
|
||||||
|
mqtt_publish(stopic, svalue);
|
||||||
|
do_cmnd_power(1, 1);
|
||||||
|
} else {
|
||||||
|
snprintf_P(svalue, sizeof(stopic), PSTR("{\"MaxPowerReachedRetry\":\"%s\"}"), MQTT_STATUS_OFF);
|
||||||
|
mqtt_publish(stopic, svalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max Energy
|
||||||
|
if (sysCfg.hlw_mkwh) {
|
||||||
|
uped = (uint16_t)(ped * 1000);
|
||||||
|
if (!hlw_mkwh_state && (rtcTime.Hour == sysCfg.hlw_mkwhs)) {
|
||||||
|
hlw_mkwh_state = 1;
|
||||||
|
snprintf_P(svalue, sizeof(stopic), PSTR("{\"EnergyMonitor\":\"%s\"}"), MQTT_STATUS_ON);
|
||||||
|
mqtt_publish(stopic, svalue);
|
||||||
|
do_cmnd_power(1, 1);
|
||||||
|
}
|
||||||
|
else if ((hlw_mkwh_state == 1) && (uped >= sysCfg.hlw_mkwh)) {
|
||||||
|
hlw_mkwh_state = 2;
|
||||||
|
dtostrf(ped, 1, 3, svalue);
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("{\"MaxEnergyReached\":\"%s%s\"}"), svalue, (sysCfg.value_units) ? " kWh" : "");
|
||||||
|
mqtt_publish(stopic, svalue);
|
||||||
|
do_cmnd_power(1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // FEATURE_POWER_LIMIT
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Presentation
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
void hlw_mqttPresent(uint8_t domidx)
|
||||||
|
{
|
||||||
|
char stopic[TOPSZ], svalue[MESSZ], stime[21], stemp0[10], stemp1[10], stemp2[10], stemp3[10];
|
||||||
|
float ped, pi, pc;
|
||||||
|
uint16_t pe, pw, pu;
|
||||||
|
|
||||||
|
snprintf_P(stime, sizeof(stime), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"),
|
||||||
|
rtcTime.Year, rtcTime.Month, rtcTime.Day, rtcTime.Hour, rtcTime.Minute, rtcTime.Second);
|
||||||
|
hlw_readEnergy(1, ped, pe, pw, pu, pi, pc);
|
||||||
|
dtostrf((float)sysCfg.hlw_kWhyesterday / 100000000, 1, 3, stemp0);
|
||||||
|
dtostrf(ped, 1, 3, stemp1);
|
||||||
|
dtostrf(pc, 1, 2, stemp2);
|
||||||
|
dtostrf(pi, 1, 3, stemp3);
|
||||||
|
snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/TELEMETRY"), PUB_PREFIX2, sysCfg.mqtt_topic);
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\", \"Energy\":{\"Yesterday\":\"%s\", \"Today\":\"%s\", \"Period\":%d, \"Power\":%d, \"Factor\":\"%s\", \"Voltage\":%d, \"Current\":\"%s\"}}"),
|
||||||
|
stime, stemp0, stemp1, pe, pw, stemp2, pu, stemp3);
|
||||||
|
mqtt_publish(stopic, svalue);
|
||||||
|
#ifdef USE_DOMOTICZ
|
||||||
|
dtostrf(ped * 1000, 1, 1, stemp1);
|
||||||
|
domoticz_sensor4(pw, stemp1);
|
||||||
|
#endif // USE_DOMOTICZ
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
String hlw_webPresent()
|
||||||
|
{
|
||||||
|
char stemp[10];
|
||||||
|
float ped, pi, pc;
|
||||||
|
uint16_t pe, pw, pu;
|
||||||
|
String page = "";
|
||||||
|
|
||||||
|
hlw_readEnergy(0, ped, pe, pw, pu, pi, pc);
|
||||||
|
page += F("<tr><td>Voltage: </td><td>"); page += String(pu); page += F(" V</td></tr>");
|
||||||
|
dtostrf(pi, 1, 3, stemp);
|
||||||
|
page += F("<tr><td>Current: </td><td>"); page += stemp; page += F(" A</td></tr>");
|
||||||
|
page += F("<tr><td>Power: </td><td>"); page += String(pw); page += F(" W</td></tr>");
|
||||||
|
dtostrf(pc, 1, 2, stemp);
|
||||||
|
page += F("<tr><td>Power Factor: </td><td>"); page += stemp; page += F("</td></tr>");
|
||||||
|
dtostrf(ped, 1, 3, stemp);
|
||||||
|
page += F("<tr><td>Energy Today: </td><td>"); page += stemp; page += F(" kWh</td></tr>");
|
||||||
|
dtostrf((float)sysCfg.hlw_kWhyesterday / 100000000, 1, 3, stemp);
|
||||||
|
page += F("<tr><td>Energy Yesterday: </td><td>"); page += stemp; page += F(" kWh</td></tr>");
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
|
|
@ -0,0 +1,271 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Heiko Krupp. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_I2C
|
||||||
|
#ifdef USE_HTU
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* HTU21 - Temperature and Humidy
|
||||||
|
*
|
||||||
|
* Source: Heiko Krupp
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define HTU21_ADDR 0x40
|
||||||
|
|
||||||
|
#define HTU21_CHIPID 0x32
|
||||||
|
|
||||||
|
#define HTU21_READTEMP 0xE3
|
||||||
|
#define HTU21_READHUM 0xE5
|
||||||
|
#define HTU21_WRITEREG 0xE6
|
||||||
|
#define HTU21_READREG 0xE7
|
||||||
|
#define HTU21_RESET 0xFE
|
||||||
|
#define HTU21_HEATER_WRITE 0x51
|
||||||
|
#define HTU21_HEATER_READ 0x11
|
||||||
|
#define HTU21_SERIAL2_READ1 0xFC /* Read 3rd two Serial bytes */
|
||||||
|
#define HTU21_SERIAL2_READ2 0xC9 /* Read 4th two Serial bytes */
|
||||||
|
|
||||||
|
#define HTU21_HEATER_ON 0x04
|
||||||
|
#define HTU21_HEATER_OFF 0xFB
|
||||||
|
|
||||||
|
#define HTU21_RES_RH12_T14 0x00 // Default
|
||||||
|
#define HTU21_RES_RH8_T12 0x01
|
||||||
|
#define HTU21_RES_RH10_T13 0x80
|
||||||
|
#define HTU21_RES_RH11_T11 0x81
|
||||||
|
|
||||||
|
#define HTU21_MAX_HUM 16 // 16ms max time
|
||||||
|
#define HTU21_MAX_TEMP 50 // 50ms max time
|
||||||
|
|
||||||
|
#define HTU21_CRC8_POLYNOM 0x13100
|
||||||
|
|
||||||
|
uint8_t htuaddr, htutype = 0;
|
||||||
|
char htustype[7];
|
||||||
|
|
||||||
|
uint8_t check_crc8(uint16_t data)
|
||||||
|
{
|
||||||
|
for (uint8_t bit = 0; bit < 16; bit++)
|
||||||
|
{
|
||||||
|
if (data & 0x8000)
|
||||||
|
data = (data << 1) ^ HTU21_CRC8_POLYNOM;
|
||||||
|
else
|
||||||
|
data <<= 1;
|
||||||
|
}
|
||||||
|
return data >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t htu21_readDeviceID(void)
|
||||||
|
{
|
||||||
|
uint16_t deviceID = 0;
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
|
||||||
|
Wire.beginTransmission(HTU21_ADDR);
|
||||||
|
Wire.write(HTU21_SERIAL2_READ1);
|
||||||
|
Wire.write(HTU21_SERIAL2_READ2);
|
||||||
|
Wire.endTransmission();
|
||||||
|
|
||||||
|
Wire.requestFrom(HTU21_ADDR, 3);
|
||||||
|
deviceID = Wire.read() << 8;
|
||||||
|
deviceID |= Wire.read();
|
||||||
|
checksum = Wire.read();
|
||||||
|
if (check_crc8(deviceID) == checksum) {
|
||||||
|
deviceID = deviceID >> 8;
|
||||||
|
} else {
|
||||||
|
deviceID = 0;
|
||||||
|
}
|
||||||
|
return (uint8_t)deviceID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void htu21_setRes(uint8_t resolution)
|
||||||
|
{
|
||||||
|
uint8_t current = i2c_read8(HTU21_ADDR, HTU21_READREG);
|
||||||
|
current &= 0x7E; // Replace current resolution bits with 0
|
||||||
|
current |= resolution; // Add new resolution bits to register
|
||||||
|
i2c_write8(HTU21_ADDR, HTU21_WRITEREG, current);
|
||||||
|
}
|
||||||
|
|
||||||
|
void htu21_reset(void)
|
||||||
|
{
|
||||||
|
Wire.beginTransmission(HTU21_ADDR);
|
||||||
|
Wire.write(HTU21_RESET);
|
||||||
|
Wire.endTransmission();
|
||||||
|
delay(15); // Reset takes 15ms
|
||||||
|
}
|
||||||
|
|
||||||
|
void htu21_heater(uint8_t heater)
|
||||||
|
{
|
||||||
|
uint8_t current = i2c_read8(HTU21_ADDR, HTU21_READREG);
|
||||||
|
|
||||||
|
switch(heater)
|
||||||
|
{
|
||||||
|
case HTU21_HEATER_ON : current |= heater;
|
||||||
|
break;
|
||||||
|
case HTU21_HEATER_OFF : current &= heater;
|
||||||
|
break;
|
||||||
|
default : current &= heater;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i2c_write8(HTU21_ADDR, HTU21_WRITEREG, current);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean htu21_init()
|
||||||
|
{
|
||||||
|
htu21_reset();
|
||||||
|
htu21_heater(HTU21_HEATER_OFF);
|
||||||
|
htu21_setRes(HTU21_RES_RH12_T14);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float htu21_convertCtoF(float c)
|
||||||
|
{
|
||||||
|
return c * 1.8 + 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
float htu21_readHumidity(void)
|
||||||
|
{
|
||||||
|
uint8_t checksum=0;
|
||||||
|
uint16_t sensorval=0;
|
||||||
|
float humidity=0.0;
|
||||||
|
|
||||||
|
Wire.beginTransmission(HTU21_ADDR);
|
||||||
|
Wire.write(HTU21_READHUM);
|
||||||
|
if(Wire.endTransmission() != 0) return 0.0; // In case of error
|
||||||
|
delay(HTU21_MAX_HUM); // HTU21 time at max resolution
|
||||||
|
|
||||||
|
Wire.requestFrom(HTU21_ADDR, 3);
|
||||||
|
if(3 <= Wire.available())
|
||||||
|
{
|
||||||
|
sensorval = Wire.read() << 8; // MSB
|
||||||
|
sensorval |= Wire.read(); // LSB
|
||||||
|
checksum = Wire.read();
|
||||||
|
}
|
||||||
|
if(check_crc8(sensorval) != checksum) return 0.0; // Checksum mismatch
|
||||||
|
|
||||||
|
sensorval ^= 0x02; // clear status bits
|
||||||
|
humidity = 0.001907 * (float)sensorval - 6;
|
||||||
|
|
||||||
|
if(humidity>100) return 100.0;
|
||||||
|
if(humidity<0) return 0.01;
|
||||||
|
|
||||||
|
return humidity;
|
||||||
|
}
|
||||||
|
|
||||||
|
float htu21_readTemperature(bool S)
|
||||||
|
{
|
||||||
|
uint8_t checksum=0;
|
||||||
|
uint16_t sensorval=0;
|
||||||
|
float t;
|
||||||
|
|
||||||
|
Wire.beginTransmission(HTU21_ADDR);
|
||||||
|
Wire.write(HTU21_READTEMP);
|
||||||
|
if(Wire.endTransmission() != 0) return 0.0; // In case of error
|
||||||
|
delay(HTU21_MAX_TEMP); // HTU21 time at max resolution
|
||||||
|
|
||||||
|
Wire.requestFrom(HTU21_ADDR, 3);
|
||||||
|
if(3 == Wire.available())
|
||||||
|
{
|
||||||
|
sensorval = Wire.read() << 8; // MSB
|
||||||
|
sensorval |= Wire.read(); // LSB
|
||||||
|
checksum = Wire.read();
|
||||||
|
}
|
||||||
|
if(check_crc8(sensorval) != checksum) return 0.0; // Checksum mismatch
|
||||||
|
|
||||||
|
t = (0.002681 * (float)sensorval - 46.85);
|
||||||
|
if(S) t = htu21_convertCtoF(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
float htu21_compensatedHumidity(float humidity, float temperature)
|
||||||
|
{
|
||||||
|
if(humidity == 0.00 && temperature == 0.00) return 0.0;
|
||||||
|
if(temperature > 0.00 && temperature < 80.00)
|
||||||
|
return (-0.15)*(25-temperature)+humidity;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t htu_detect()
|
||||||
|
{
|
||||||
|
if (htutype) return true;
|
||||||
|
|
||||||
|
char log[LOGSZ];
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
htuaddr = HTU21_ADDR;
|
||||||
|
htutype = htu21_readDeviceID();
|
||||||
|
snprintf_P(htustype, sizeof(htustype), PSTR("HTU"));
|
||||||
|
switch (htutype) {
|
||||||
|
case HTU21_CHIPID:
|
||||||
|
success = htu21_init();
|
||||||
|
snprintf_P(htustype, sizeof(htustype), PSTR("HTU21"));
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("I2C: %s found at address 0x%x"), htustype, htuaddr);
|
||||||
|
addLog(LOG_LEVEL_DEBUG, log);
|
||||||
|
} else {
|
||||||
|
htutype = 0;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Presentation
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
void htu_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx)
|
||||||
|
{
|
||||||
|
if (!htutype) return;
|
||||||
|
|
||||||
|
char stemp1[10], stemp2[10];
|
||||||
|
|
||||||
|
float t = htu21_readTemperature(TEMP_CONVERSION);
|
||||||
|
float h = htu21_readHumidity();
|
||||||
|
h = htu21_compensatedHumidity(h, t);
|
||||||
|
dtostrf(t, 1, TEMP_RESOLUTION &3, stemp1);
|
||||||
|
dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp2);
|
||||||
|
snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Temperature\":\"%s\", \"Humidity\":\"%s\"}"), svalue, htustype, stemp1, stemp2);
|
||||||
|
*djson = 1;
|
||||||
|
#ifdef USE_DOMOTICZ
|
||||||
|
domoticz_sensor2(stemp1, stemp2);
|
||||||
|
#endif // USE_DOMOTICZ
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
String htu_webPresent()
|
||||||
|
{
|
||||||
|
String page = "";
|
||||||
|
if (htutype) {
|
||||||
|
char itemp[10], iconv[10];
|
||||||
|
|
||||||
|
snprintf_P(iconv, sizeof(iconv), PSTR("°%c"), (TEMP_CONVERSION) ? 'F' : 'C');
|
||||||
|
float t_htu21 = htu21_readTemperature(TEMP_CONVERSION);
|
||||||
|
float h_htu21 = htu21_readHumidity();
|
||||||
|
h_htu21 = htu21_compensatedHumidity(h_htu21, t_htu21);
|
||||||
|
dtostrf(t_htu21, 1, TEMP_RESOLUTION &3, itemp);
|
||||||
|
page += F("<tr><td>HTU Temperature: </td><td>"); page += itemp; page += iconv; page += F("</td></tr>");
|
||||||
|
dtostrf(h_htu21, 1, HUMIDITY_RESOLUTION &3, itemp);
|
||||||
|
page += F("<tr><td>HTU Humidity: </td><td>"); page += itemp; page += F("%</td></tr>");
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
#endif // USE_HTU
|
||||||
|
#endif // USE_I2C
|
||||||
|
|
Loading…
Reference in New Issue