Compare commits
No commits in common. "v3.9.15" and "master" have entirely different histories.
365
.gitignore
vendored
365
.gitignore
vendored
@ -1,4 +1,361 @@
|
|||||||
.pioenvs
|
# ---> C++
|
||||||
.piolibdeps
|
# Prerequisites
|
||||||
.clang_complete
|
*.d
|
||||||
.gcc-flags.json
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# ---> C
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Object files
|
||||||
|
*.o
|
||||||
|
*.ko
|
||||||
|
*.obj
|
||||||
|
*.elf
|
||||||
|
|
||||||
|
# Linker output
|
||||||
|
*.ilk
|
||||||
|
*.map
|
||||||
|
*.exp
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# Shared objects (inc. Windows DLLs)
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.i*86
|
||||||
|
*.x86_64
|
||||||
|
*.hex
|
||||||
|
|
||||||
|
# Debug files
|
||||||
|
*.dSYM/
|
||||||
|
*.su
|
||||||
|
*.idb
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Kernel Module Compile Results
|
||||||
|
*.mod*
|
||||||
|
*.cmd
|
||||||
|
.tmp_versions/
|
||||||
|
modules.order
|
||||||
|
Module.symvers
|
||||||
|
Mkfile.old
|
||||||
|
dkms.conf
|
||||||
|
|
||||||
|
# ---> CMake
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Testing
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps
|
||||||
|
|
||||||
|
# ---> JetBrains
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
# ---> Linux
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
# ---> Ninja
|
||||||
|
.ninja_deps
|
||||||
|
.ninja_log
|
||||||
|
|
||||||
|
# ---> Python
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
#pdm.lock
|
||||||
|
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||||
|
# in version control.
|
||||||
|
# https://pdm.fming.dev/#use-with-ide
|
||||||
|
.pdm.toml
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
|
|||||||
20
.travis.yml
20
.travis.yml
@ -1,20 +0,0 @@
|
|||||||
language: python
|
|
||||||
python:
|
|
||||||
- '2.7'
|
|
||||||
sudo: false
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- "~/.platformio"
|
|
||||||
install:
|
|
||||||
- pip install -U platformio
|
|
||||||
|
|
||||||
script:
|
|
||||||
- platformio run
|
|
||||||
deploy:
|
|
||||||
provider: releases
|
|
||||||
api_key:
|
|
||||||
secure: I5x8qJ5+229qJv5jSnNPGERQHl0NSKvrVHdpVzr/HOo2zeZ/Q5sMhHWo3IBD3AKjGdSlpyNApDwYTaGvenMe+xtUWSSxYIy2ptWAWfkpOtUMx3lI3brZJRt8s98xS5m972SC9mlNT2ZU+i6hZ6srYv2w4nDuyX+j7Q6IGqvYtabxUWzza/Zg0yNpPScvvzscW1CVhdEd5qYH6OKfBfuVOj3ZG4pCycvbejhkUJwbCQ5m8+DEXUol8BKeh92+TPC3jDHXWIStdgLIrmkZ3YWxMQBgQ41QIkaf6X1/0WYEcY0DFW6hlDzg2GbJ8tPRRPC9dfgMs3ZMKJkc7e4x7wMvG2QXQ0aO6e7xTMw41JZ/OrIit0JDHB1M8bWDPUhHwjiCht4W77n7KWFk9sIUDzOdMdd69BIMt5IohtkjnIT2dXekB4xiNvfPLYUa70aOuSHWi3HXVSE1R7RX0brmNf/mH1Pm91uun3UqtIwhrpD0gteQnc0EAlHoOJOazdn3cohrtmECZJo+f+EiqFfEHT2hBrHPEvWknNfxAyPS7jYWKQ7pTMk+y/BUkLyIQkimvNz41azA6sA75nnQrZ+ZJQa+KP2cEObMBs/ekzA45nds1UXpolI1W8QIOxJ/Y10C1yxr6V5a3WWg1H8EbF0HaqiyIeQx/UCz7gl62CbLEDui9PA=
|
|
||||||
file: ".pioenvs/sonoff/firmware.bin"
|
|
||||||
skip_cleanup: true
|
|
||||||
on:
|
|
||||||
tags: true
|
|
||||||
9
LICENSE
Normal file
9
LICENSE
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 mgeppert
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
33
README.md
33
README.md
@ -1,32 +1,3 @@
|
|||||||
## Sonoff-Tasmota
|
# Tasmota
|
||||||
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.15** - See ```sonoff/_releasenotes.ino``` for change information.
|
Local copy of the https://github.com/arendst/Tasmota#
|
||||||
|
|
||||||
- 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.
|
|
||||||
|
|
||||||
<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-Tasmota/wiki) for more information.<br />
|
|
||||||
See [Community](https://groups.google.com/d/forum/sonoffusers) for forum and more user experience.
|
|
||||||
|
|
||||||
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" />
|
|
||||||
Binary file not shown.
@ -1,15 +0,0 @@
|
|||||||
<?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";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@ -1,112 +0,0 @@
|
|||||||
#!/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
@ -1,130 +0,0 @@
|
|||||||
|
|
||||||
# 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"
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
; PlatformIO Project Configuration File
|
|
||||||
;
|
|
||||||
; Build options: build flags, source filter, extra scripting
|
|
||||||
; Upload options: custom port, speed and extra flags
|
|
||||||
; Library options: dependencies, extra library storages
|
|
||||||
;
|
|
||||||
; Please visit documentation for the other options and examples
|
|
||||||
; http://docs.platformio.org/en/stable/projectconf.html
|
|
||||||
|
|
||||||
[platformio]
|
|
||||||
src_dir = sonoff
|
|
||||||
|
|
||||||
[env:sonoff]
|
|
||||||
platform = espressif8266
|
|
||||||
framework = arduino
|
|
||||||
; ESP8266 - Sonoff Basic et al.
|
|
||||||
board = esp01_1m
|
|
||||||
; ESP8285 - Sonoff Touch and Sonoff 4CH
|
|
||||||
; board = esp8285
|
|
||||||
build_flags = -Wl,-Tesp8266.flash.1m64.ld -DMQTT_MAX_PACKET_SIZE=400
|
|
||||||
|
|
||||||
lib_deps = PubSubClient, NeoPixelBus
|
|
||||||
@ -1,567 +0,0 @@
|
|||||||
/* 3.9.15 20170213
|
|
||||||
* Change JSON float values from string to number according to http://json.org (#56)
|
|
||||||
* Add support for exs latched relay module https://ex-store.de/ESP8266-WiFi-Relay-V31 (#58)
|
|
||||||
* Add support for inverted relays
|
|
||||||
* Changed MAX_LOG_LINES from 70 to 60 to preserve memory
|
|
||||||
*
|
|
||||||
* 3.9.14 20170211
|
|
||||||
* Add False and True as alternatives for 0/Off and 1/On (#49)
|
|
||||||
* Fix Status10 JSON format (#52)
|
|
||||||
* Fix DS18x20 using OneWire library (#53)
|
|
||||||
*
|
|
||||||
* 3.9.13 20170210
|
|
||||||
* Add FlashChipMode to Status 4
|
|
||||||
* Removed redundant DHT2 option and code
|
|
||||||
* Add Sonoff SV GPIO pin 05 configuration (#40)
|
|
||||||
* Add configuration file backup and restore via web page
|
|
||||||
* Fix latency due to light_sleep mode even if sleep was set to zero (#50)
|
|
||||||
*
|
|
||||||
* 3.9.12 20170208
|
|
||||||
* Fix compile error when webserver is disabled (#30)
|
|
||||||
* Fix possible ESP8285 flash problem by updating Flash Chip Mode to DOUT during OTA upload
|
|
||||||
* Fix hostname issues by not allowing user entry of string formatting and removing from user_config.h (#36)
|
|
||||||
*
|
|
||||||
* 3.9.11 20170204
|
|
||||||
* Fix command I2Cscan
|
|
||||||
* Fix not allowed spaces in Topic, ButtonTopic and SwitchTopic
|
|
||||||
* Make all TELEMETRY, STATUS and COMMAND message topics unique (#4)
|
|
||||||
* Advertise command topic to be used by iobroker (#299)
|
|
||||||
* Fix butten (non)detection if no GPIO_KEY1 is defined (#13)
|
|
||||||
* Change WeMo serialnumber from 7 decimal chars to 8 hexadecimal chars (#18)
|
|
||||||
* Update web page with Build Date/Time, Emulation and mDNS Discovery and Advertise information (#21)
|
|
||||||
*
|
|
||||||
* 3.9.10 20170130
|
|
||||||
* Add WS2812 Color Type selection (RGB or GRB) to user_config.h (#7)
|
|
||||||
* Hue api changes to support HUE App(s) (#8)
|
|
||||||
*
|
|
||||||
* 3.9.9 20170130
|
|
||||||
* Add command status 10 showing sensor data
|
|
||||||
* Fix hlw status messages if hlw is disabled
|
|
||||||
*
|
|
||||||
* 3.9.8 20170130
|
|
||||||
* Remove GPIO07 and GPIO08 from user selectable (#5)
|
|
||||||
*
|
|
||||||
* 3.9.7 20170129
|
|
||||||
* Fix possible WS2812 exceptions when using emulation
|
|
||||||
* Add command Emulation to dynamic configure Belkin WeMo and Hue Bridge for Alexa
|
|
||||||
*
|
|
||||||
* 3.9.6 20170129
|
|
||||||
* Add dynamic sleep for WS2812 animation (#1)
|
|
||||||
*
|
|
||||||
* 3.9.5 20170128
|
|
||||||
* Fix error message in case of wrong Domoticz command
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
2649
sonoff/sonoff.ino
2649
sonoff/sonoff.ino
File diff suppressed because it is too large
Load Diff
@ -1,286 +0,0 @@
|
|||||||
/*********************************************************************************************\
|
|
||||||
* Template parameters
|
|
||||||
\*********************************************************************************************/
|
|
||||||
|
|
||||||
// User selectable GPIO functionality
|
|
||||||
enum upins_t {
|
|
||||||
GPIO_NONE, // Not used
|
|
||||||
GPIO_DHT11, // DHT11
|
|
||||||
GPIO_DHT21, // DHT21, AM2301
|
|
||||||
GPIO_DHT22, // DHT22, AM2302, AM2321
|
|
||||||
GPIO_DSB, // Single wire DS18B20 or DS18S20
|
|
||||||
GPIO_I2C_SCL, // I2C SCL
|
|
||||||
GPIO_I2C_SDA, // I2C SDA
|
|
||||||
GPIO_WS2812, // WS2812 Led string
|
|
||||||
GPIO_SWT1, // User connected external switches
|
|
||||||
GPIO_SENSOR_END };
|
|
||||||
|
|
||||||
// Text in webpage Module Parameters and commands GPIOS and GPIO
|
|
||||||
const char sensors[GPIO_SENSOR_END][8] PROGMEM = {
|
|
||||||
"None",
|
|
||||||
"DHT11",
|
|
||||||
"AM2301",
|
|
||||||
"DHT22",
|
|
||||||
"DS18x20",
|
|
||||||
"I2C SCL",
|
|
||||||
"I2C SDA",
|
|
||||||
"WS2812",
|
|
||||||
"Switch" };
|
|
||||||
|
|
||||||
// Programmer selectable GPIO functionality offset by user selectable GPIOs
|
|
||||||
enum fpins_t {
|
|
||||||
GPIO_SWT2 = GPIO_SENSOR_END,
|
|
||||||
GPIO_SWT3,
|
|
||||||
GPIO_SWT4,
|
|
||||||
GPIO_KEY1, // Button usually connected to GPIO0
|
|
||||||
GPIO_KEY2,
|
|
||||||
GPIO_KEY3,
|
|
||||||
GPIO_KEY4,
|
|
||||||
GPIO_REL1, // Relays
|
|
||||||
GPIO_REL2,
|
|
||||||
GPIO_REL3,
|
|
||||||
GPIO_REL4,
|
|
||||||
GPIO_REL1_INV,
|
|
||||||
GPIO_REL2_INV,
|
|
||||||
GPIO_REL3_INV,
|
|
||||||
GPIO_REL4_INV,
|
|
||||||
GPIO_LED1, // Leds
|
|
||||||
GPIO_LED2,
|
|
||||||
GPIO_LED3,
|
|
||||||
GPIO_LED4,
|
|
||||||
GPIO_LED1_INV,
|
|
||||||
GPIO_LED2_INV,
|
|
||||||
GPIO_LED3_INV,
|
|
||||||
GPIO_LED4_INV,
|
|
||||||
GPIO_PWM0, // Cold
|
|
||||||
GPIO_PWM1, // Warm
|
|
||||||
GPIO_PWM2, // Red (swapped with Blue from original)
|
|
||||||
GPIO_PWM3, // Green
|
|
||||||
GPIO_PWM4, // Blue (swapped with Red from original)
|
|
||||||
GPIO_RXD, // Serial interface
|
|
||||||
GPIO_TXD, // Serial interface
|
|
||||||
GPIO_HLW_SEL, // HLW8012 Sel output (Sonoff Pow)
|
|
||||||
GPIO_HLW_CF1, // HLW8012 CF1 voltage / current (Sonoff Pow)
|
|
||||||
GPIO_HLW_CF, // HLW8012 CF power (Sonoff Pow)
|
|
||||||
GPIO_USER, // User configurable
|
|
||||||
GPIO_MAX };
|
|
||||||
|
|
||||||
/********************************************************************************************/
|
|
||||||
|
|
||||||
// Supported hardware modules
|
|
||||||
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,
|
|
||||||
EXS_RELAY,
|
|
||||||
USER_TEST,
|
|
||||||
MAXMODULE };
|
|
||||||
|
|
||||||
/********************************************************************************************/
|
|
||||||
|
|
||||||
#define MAX_GPIO_PIN 17 // Number of supported GPIO
|
|
||||||
|
|
||||||
typedef struct MYIO {
|
|
||||||
uint8_t io[MAX_GPIO_PIN];
|
|
||||||
} myio;
|
|
||||||
|
|
||||||
typedef struct MYTMPLT {
|
|
||||||
char name[16];
|
|
||||||
myio gp;
|
|
||||||
} mytmplt;
|
|
||||||
|
|
||||||
// Default module settings
|
|
||||||
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
|
|
||||||
GPIO_USER, // GPIO05 Optional sensor
|
|
||||||
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
|
|
||||||
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
|
||||||
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, 0, 0,
|
|
||||||
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)
|
|
||||||
},
|
|
||||||
{ "EXS Relay", // Latching relay https://ex-store.de/ESP8266-WiFi-Relay-V31
|
|
||||||
// Module Pin 1 VCC 3V3, Module Pin 6 GND
|
|
||||||
GPIO_KEY1, // GPIO00 Module Pin 8 - Button (firmware flash)
|
|
||||||
GPIO_USER, // GPIO01 Module Pin 2 = UART0_TXD
|
|
||||||
GPIO_USER, // GPIO02 Module Pin 7
|
|
||||||
GPIO_USER, // GPIO03 Module Pin 3 = UART0_RXD
|
|
||||||
GPIO_USER, // GPIO04 Module Pin 10
|
|
||||||
GPIO_USER, // GPIO05 Module Pin 9
|
|
||||||
0, 0, 0, 0, 0, 0,
|
|
||||||
GPIO_REL1, // GPIO12 Relay1 ( 1 = Off)
|
|
||||||
GPIO_REL2, // GPIO13 Relay1 ( 1 = On)
|
|
||||||
GPIO_USER, // GPIO14 Module Pin 5
|
|
||||||
0,
|
|
||||||
GPIO_USER // GPIO16 Module Pin 4
|
|
||||||
},
|
|
||||||
{ "User Test", // Sonoff Basic User Test
|
|
||||||
GPIO_KEY1, // GPIO00 Button
|
|
||||||
0,
|
|
||||||
GPIO_USER, // GPIO02 Optional sensor
|
|
||||||
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
|
||||||
GPIO_USER, // GPIO04 Optional sensor
|
|
||||||
GPIO_USER, // GPIO05 Optional sensor
|
|
||||||
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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
#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
|
|
||||||
1016
sonoff/support.ino
1016
sonoff/support.ino
File diff suppressed because it is too large
Load Diff
@ -1,139 +0,0 @@
|
|||||||
/*********************************************************************************************\
|
|
||||||
* 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_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) - Disable by //
|
|
||||||
// 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 (+7k 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 (+60k code, +4k mem) - Disable by //
|
|
||||||
#define FRIENDLY_NAME "Sonoff" // [FriendlyName] Friendlyname up to 32 characters used by webpages and Alexa
|
|
||||||
#define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin)
|
|
||||||
#define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+11k code, +2k mem)
|
|
||||||
#define EMULATION EMUL_NONE // [Emulation] Select Belkin WeMo or Hue Bridge emulation (EMUL_NONE, EMUL_WEMO or EMUL_HUE)
|
|
||||||
|
|
||||||
// -- mDNS ----------------------------------------
|
|
||||||
#define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem) - Disable by //
|
|
||||||
#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_DS18x20 // Optional using OneWire library for multiple DS18B20 and/or DS18S20
|
|
||||||
|
|
||||||
#define USE_I2C // I2C using library wire (+10k code, 0.2k mem) - Disable by //
|
|
||||||
#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 using library NeoPixelBus (+8k code, +1k mem) - Disable by //
|
|
||||||
#define USE_WS2812_CTYPE 1 // WS2812 Color type (0 - RGB, 1 - GRB)
|
|
||||||
// #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 (ARDUINO < 10610)
|
|
||||||
#error "This software is supported with Arduino IDE starting from 1.6.10 and ESP8266 Release 2.3.0"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
/*****************************************************************************************************\
|
|
||||||
* 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"
|
|
||||||
|
|
||||||
1702
sonoff/webserver.ino
1702
sonoff/webserver.ino
File diff suppressed because it is too large
Load Diff
@ -1,389 +0,0 @@
|
|||||||
/*
|
|
||||||
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;
|
|
||||||
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
|
|
||||||
\*********************************************************************************************/
|
|
||||||
|
|
||||||
boolean domoticz_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue)
|
|
||||||
{
|
|
||||||
boolean serviced = true;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
serviced = false;
|
|
||||||
}
|
|
||||||
return serviced;
|
|
||||||
}
|
|
||||||
|
|
||||||
void domoticz_commands(char *svalue, uint16_t ssvalue)
|
|
||||||
{
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"Commands4\":\"DomoticzInTopic, DomoticzOutTopic, DomoticzIdx, DomoticzKeyIdx, DomoticzSwitchIdx, DomoticzSensorIdx, DomoticzUpdateTimer\"}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
\*********************************************************************************************/
|
|
||||||
|
|
||||||
#ifdef USE_WEBSERVER
|
|
||||||
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_WEBSERVER
|
|
||||||
#endif // USE_DOMOTICZ
|
|
||||||
|
|
||||||
@ -1,220 +0,0 @@
|
|||||||
/*
|
|
||||||
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_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
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* 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[16];
|
|
||||||
snprintf_P(serial, sizeof(serial), PSTR("201612K%08X"), ESP.getChipId());
|
|
||||||
return String(serial);
|
|
||||||
}
|
|
||||||
|
|
||||||
String wemo_UUID()
|
|
||||||
{
|
|
||||||
char uuid[27];
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* 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();
|
|
||||||
// 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();
|
|
||||||
// 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("3 response packets 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************************************/
|
|
||||||
|
|
||||||
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) {
|
|
||||||
if ((sysCfg.emulation == EMUL_WEMO) &&(request.indexOf("urn:Belkin:device:**") > 0)) {
|
|
||||||
wemo_respondToMSearch();
|
|
||||||
}
|
|
||||||
else if ((sysCfg.emulation == EMUL_HUE) && ((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_EMULATION
|
|
||||||
|
|
||||||
@ -1,586 +0,0 @@
|
|||||||
/*
|
|
||||||
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
|
|
||||||
#if (USE_WS2812_CTYPE == 1)
|
|
||||||
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> *strip = NULL;
|
|
||||||
#else // USE_WS2812_CTYPE
|
|
||||||
NeoPixelBus<NeoRgbFeature, Neo800KbpsMethod> *strip = NULL;
|
|
||||||
#endif // USE_WS2812_CTYPE
|
|
||||||
#else // USE_WS2812_DMA
|
|
||||||
#if (USE_WS2812_CTYPE == 1)
|
|
||||||
NeoPixelBus<NeoGrbFeature, NeoEsp8266BitBang800KbpsMethod> *strip = NULL;
|
|
||||||
#else // USE_WS2812_CTYPE
|
|
||||||
NeoPixelBus<NeoRgbFeature, NeoEsp8266BitBang800KbpsMethod> *strip = NULL;
|
|
||||||
#endif // USE_WS2812_CTYPE
|
|
||||||
#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
|
|
||||||
sleep = sysCfg.sleep;
|
|
||||||
stripTimerCntr = 0;
|
|
||||||
tcolor = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sleep = 0;
|
|
||||||
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
|
|
||||||
#if (USE_WS2812_CTYPE == 1)
|
|
||||||
strip = new NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod>(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use.
|
|
||||||
#else // USE_WS2812_CTYPE
|
|
||||||
strip = new NeoPixelBus<NeoRgbFeature, Neo800KbpsMethod>(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use.
|
|
||||||
#endif // USE_WS2812_CTYPE
|
|
||||||
#else // USE_WS2812_DMA
|
|
||||||
#if (USE_WS2812_CTYPE == 1)
|
|
||||||
strip = new NeoPixelBus<NeoGrbFeature, NeoEsp8266BitBang800KbpsMethod>(WS2812_MAX_LEDS, pin[GPIO_WS2812]);
|
|
||||||
#else // USE_WS2812_CTYPE
|
|
||||||
strip = new NeoPixelBus<NeoRgbFeature, NeoEsp8266BitBang800KbpsMethod>(WS2812_MAX_LEDS, pin[GPIO_WS2812]);
|
|
||||||
#endif // USE_WS2812_CTYPE
|
|
||||||
#endif // USE_WS2812_DMA
|
|
||||||
strip->Begin();
|
|
||||||
ws2812_pixels();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* Commands
|
|
||||||
\*********************************************************************************************/
|
|
||||||
|
|
||||||
boolean ws2812_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue)
|
|
||||||
{
|
|
||||||
boolean serviced = true;
|
|
||||||
|
|
||||||
if (!strcmp(type,"PIXELS")) {
|
|
||||||
if ((data_len > 0) && (payload > 0) && (payload <= WS2812_MAX_LEDS)) {
|
|
||||||
sysCfg.ws_pixels = payload;
|
|
||||||
ws2812_pixels();
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"Pixels\":%d}"), sysCfg.ws_pixels);
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"LED") && (index > 0) && (index <= sysCfg.ws_pixels)) {
|
|
||||||
if (data_len == 6) {
|
|
||||||
// ws2812_setColor(index, dataBufUc);
|
|
||||||
ws2812_setColor(index, dataBuf);
|
|
||||||
}
|
|
||||||
ws2812_getColor(index, svalue, ssvalue);
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"COLOR")) {
|
|
||||||
if (data_len == 6) {
|
|
||||||
// ws2812_setColor(0, dataBufUc);
|
|
||||||
ws2812_setColor(0, dataBuf);
|
|
||||||
power = 1;
|
|
||||||
}
|
|
||||||
ws2812_getColor(0, svalue, ssvalue);
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"DIMMER")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload <= 100)) {
|
|
||||||
sysCfg.ws_dimmer = payload;
|
|
||||||
power = 1;
|
|
||||||
#ifdef USE_DOMOTICZ
|
|
||||||
mqtt_publishDomoticzPowerState(index);
|
|
||||||
#endif // USE_DOMOTICZ
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"Dimmer\":%d}"), sysCfg.ws_dimmer);
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"LEDTABLE")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload <= 2)) {
|
|
||||||
switch (payload) {
|
|
||||||
case 0: // Off
|
|
||||||
case 1: // On
|
|
||||||
sysCfg.ws_ledtable = payload;
|
|
||||||
break;
|
|
||||||
case 2: // Toggle
|
|
||||||
sysCfg.ws_ledtable ^= 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ws2812_update();
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"LedTable\":\"%s\"}"), (sysCfg.ws_ledtable) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"FADE")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload <= 2)) {
|
|
||||||
switch (payload) {
|
|
||||||
case 0: // Off
|
|
||||||
case 1: // On
|
|
||||||
sysCfg.ws_fade = payload;
|
|
||||||
break;
|
|
||||||
case 2: // Toggle
|
|
||||||
sysCfg.ws_fade ^= 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"Fade\":\"%s\"}"), (sysCfg.ws_fade) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"SPEED")) { // 1 - fast, 5 - slow
|
|
||||||
if ((data_len > 0) && (payload > 0) && (payload <= 5)) {
|
|
||||||
sysCfg.ws_speed = payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"Speed\":%d}"), sysCfg.ws_speed);
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"WIDTH")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload <= 4)) {
|
|
||||||
sysCfg.ws_width = payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"Width\":%d}"), sysCfg.ws_width);
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"WAKEUP")) {
|
|
||||||
if ((data_len > 0) && (payload > 0) && (payload < 3601)) {
|
|
||||||
sysCfg.ws_wakeup = payload;
|
|
||||||
if (sysCfg.ws_scheme == 1) sysCfg.ws_scheme = 0;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"WakeUp\":%d}"), sysCfg.ws_wakeup);
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"SCHEME")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload <= 9)) {
|
|
||||||
sysCfg.ws_scheme = payload;
|
|
||||||
if (sysCfg.ws_scheme == 1) ws2812_resetWakupState();
|
|
||||||
power = 1;
|
|
||||||
ws2812_resetStripTimer();
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"Scheme\":%d}"), sysCfg.ws_scheme);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
serviced = false;
|
|
||||||
}
|
|
||||||
return serviced;
|
|
||||||
}
|
|
||||||
#endif // USE_WS2812
|
|
||||||
@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,477 +0,0 @@
|
|||||||
/*
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,214 +0,0 @@
|
|||||||
/*
|
|
||||||
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 GPIO_DHT11:
|
|
||||||
h = data[0];
|
|
||||||
t = data[2];
|
|
||||||
if(S) t = dht_convertCtoF(t);
|
|
||||||
break;
|
|
||||||
case GPIO_DHT22:
|
|
||||||
case GPIO_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)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
@ -1,206 +0,0 @@
|
|||||||
/*
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
@ -1,206 +0,0 @@
|
|||||||
/*
|
|
||||||
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 = NULL;
|
|
||||||
|
|
||||||
uint8_t ds18x20_addr[DS18X20_MAX_SENSORS][8];
|
|
||||||
uint8_t ds18x20_idx[DS18X20_MAX_SENSORS];
|
|
||||||
uint8_t ds18x20_snsrs = 0;
|
|
||||||
|
|
||||||
void ds18x20_init()
|
|
||||||
{
|
|
||||||
ds = new OneWire(pin[GPIO_DSB]);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
@ -1,586 +0,0 @@
|
|||||||
/*
|
|
||||||
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 FEATURE_POWER_LIMIT true
|
|
||||||
|
|
||||||
/*********************************************************************************************/
|
|
||||||
|
|
||||||
#define HLW_PREF 10000 // 1000.0W
|
|
||||||
#define HLW_UREF 2200 // 220.0V
|
|
||||||
#define HLW_IREF 4545 // 4.545A
|
|
||||||
|
|
||||||
byte hlw_pminflg = 0;
|
|
||||||
byte hlw_pmaxflg = 0;
|
|
||||||
byte hlw_uminflg = 0;
|
|
||||||
byte hlw_umaxflg = 0;
|
|
||||||
byte hlw_iminflg = 0;
|
|
||||||
byte hlw_imaxflg = 0;
|
|
||||||
|
|
||||||
byte power_steady_cntr;
|
|
||||||
byte hlw_mkwh_state = 0;
|
|
||||||
|
|
||||||
#if FEATURE_POWER_LIMIT
|
|
||||||
byte hlw_mplr_counter = 0;
|
|
||||||
uint16_t hlw_mplh_counter = 0;
|
|
||||||
uint16_t hlw_mplw_counter = 0;
|
|
||||||
#endif // FEATURE_POWER_LIMIT
|
|
||||||
|
|
||||||
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 (rtcTime.Valid) {
|
|
||||||
if (rtc_loctime() == rtc_midnight()) {
|
|
||||||
sysCfg.hlw_kWhyesterday = hlw_kWhtoday;
|
|
||||||
hlw_kWhtoday = 0;
|
|
||||||
hlw_mkwh_state = 3;
|
|
||||||
}
|
|
||||||
if ((rtcTime.Hour == sysCfg.hlw_mkwhs) && (hlw_mkwh_state == 3)) {
|
|
||||||
hlw_mkwh_state = 0;
|
|
||||||
}
|
|
||||||
if (hlw_startup && (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_setPowerSteadyCounter(byte value)
|
|
||||||
{
|
|
||||||
power_steady_cntr = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hlw_margin_chk()
|
|
||||||
{
|
|
||||||
char log[LOGSZ], 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(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_topic_P(1, PSTR("MARGINS"), svalue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FEATURE_POWER_LIMIT
|
|
||||||
// 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_topic_P(0, PSTR("WARNING"), 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(svalue), PSTR("{\"PowerMonitor\":\"%s\"}"), MQTT_STATUS_ON);
|
|
||||||
mqtt_publish_topic_P(0, PSTR("RESULT"), svalue);
|
|
||||||
do_cmnd_power(1, 1);
|
|
||||||
} else {
|
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR("{\"MaxPowerReachedRetry\":\"%s\"}"), MQTT_STATUS_OFF);
|
|
||||||
mqtt_publish_topic_P(0, PSTR("WARNING"), 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(svalue), PSTR("{\"EnergyMonitor\":\"%s\"}"), MQTT_STATUS_ON);
|
|
||||||
mqtt_publish_topic_P(0, PSTR("RESULT"), 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_topic_P(0, PSTR("WARNING"), svalue);
|
|
||||||
do_cmnd_power(1, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // FEATURE_POWER_LIMIT
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* Commands
|
|
||||||
\*********************************************************************************************/
|
|
||||||
|
|
||||||
boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue)
|
|
||||||
{
|
|
||||||
boolean serviced = true;
|
|
||||||
|
|
||||||
if (!strcmp(type,"POWERLOW")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 3601)) {
|
|
||||||
sysCfg.hlw_pmin = payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"PowerLow\":\"%d%s\"}"), sysCfg.hlw_pmin, (sysCfg.value_units) ? " W" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"POWERHIGH")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 3601)) {
|
|
||||||
sysCfg.hlw_pmax = payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"PowerHigh\":\"%d%s\"}"), sysCfg.hlw_pmax, (sysCfg.value_units) ? " W" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"VOLTAGELOW")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 501)) {
|
|
||||||
sysCfg.hlw_umin = payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"VoltageLow\":\"%d%s\"}"), sysCfg.hlw_umin, (sysCfg.value_units) ? " V" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"VOLTAGEHIGH")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 501)) {
|
|
||||||
sysCfg.hlw_umax = payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("[\"VoltageHigh\":\"%d%s\"}"), sysCfg.hlw_umax, (sysCfg.value_units) ? " V" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"CURRENTLOW")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 16001)) {
|
|
||||||
sysCfg.hlw_imin = payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"CurrentLow\":\"%d%s\"}"), sysCfg.hlw_imin, (sysCfg.value_units) ? " mA" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"CURRENTHIGH")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 16001)) {
|
|
||||||
sysCfg.hlw_imax = payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"CurrentHigh\":\"%d%s\"}"), sysCfg.hlw_imax, (sysCfg.value_units) ? " mA" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"HLWPCAL")) {
|
|
||||||
if ((data_len > 0) && (payload > 0) && (payload < 32001)) {
|
|
||||||
sysCfg.hlw_pcal = (payload == 1) ? HLW_PREF_PULSE : payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("(\"HlwPcal\":\"%d%s\"}"), sysCfg.hlw_pcal, (sysCfg.value_units) ? " uS" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"HLWUCAL")) {
|
|
||||||
if ((data_len > 0) && (payload > 0) && (payload < 32001)) {
|
|
||||||
sysCfg.hlw_ucal = (payload == 1) ? HLW_UREF_PULSE : payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"HlwUcal\":\"%d%s\"}"), sysCfg.hlw_ucal, (sysCfg.value_units) ? " uS" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"HLWICAL")) {
|
|
||||||
if ((data_len > 0) && (payload > 0) && (payload < 32001)) {
|
|
||||||
sysCfg.hlw_ical = (payload == 1) ? HLW_IREF_PULSE : payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"HlwIcal\":\"%d%s\"}"), sysCfg.hlw_ical, (sysCfg.value_units) ? " uS" : "");
|
|
||||||
}
|
|
||||||
#if FEATURE_POWER_LIMIT
|
|
||||||
else if (!strcmp(type,"MAXPOWER")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 3601)) {
|
|
||||||
sysCfg.hlw_mpl = payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"MaxPower\":\"%d%s\"}"), sysCfg.hlw_mpl, (sysCfg.value_units) ? " W" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"MAXPOWERHOLD")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 3601)) {
|
|
||||||
sysCfg.hlw_mplh = (payload == 1) ? MAX_POWER_HOLD : payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"MaxPowerHold\":\"%d%s\"}"), sysCfg.hlw_mplh, (sysCfg.value_units) ? " Sec" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"MAXPOWERWINDOW")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 3601)) {
|
|
||||||
sysCfg.hlw_mplw = (payload == 1) ? MAX_POWER_WINDOW : payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"MaxPowerWindow\":\"%d%s\"}"), sysCfg.hlw_mplw, (sysCfg.value_units) ? " Sec" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"SAFEPOWER")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 3601)) {
|
|
||||||
sysCfg.hlw_mspl = payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"SafePower\":\"%d%s\"}"), sysCfg.hlw_mspl, (sysCfg.value_units) ? " W" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"SAFEPOWERHOLD")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 3601)) {
|
|
||||||
sysCfg.hlw_msplh = (payload == 1) ? SAFE_POWER_HOLD : payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"SafePowerHold\":\"%d%s\"}"), sysCfg.hlw_msplh, (sysCfg.value_units) ? " Sec" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"SAFEPOWERWINDOW")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 1440)) {
|
|
||||||
sysCfg.hlw_msplw = (payload == 1) ? SAFE_POWER_WINDOW : payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"SafePowerWindow\":\"%d%s\"}"), sysCfg.hlw_msplw, (sysCfg.value_units) ? " Min" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"MAXENERGY")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 3601)) {
|
|
||||||
sysCfg.hlw_mkwh = payload;
|
|
||||||
hlw_mkwh_state = 3;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"MaxEnergy\":\"%d%s\"}"), sysCfg.hlw_mkwh, (sysCfg.value_units) ? " Wh" : "");
|
|
||||||
}
|
|
||||||
else if (!strcmp(type,"MAXENERGYSTART")) {
|
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < 24)) {
|
|
||||||
sysCfg.hlw_mkwhs = payload;
|
|
||||||
}
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"MaxEnergyStart\":\"%d%s\"}"), sysCfg.hlw_mkwhs, (sysCfg.value_units) ? " Hr" : "");
|
|
||||||
}
|
|
||||||
#endif // FEATURE_POWER_LIMIT
|
|
||||||
else {
|
|
||||||
serviced = false;
|
|
||||||
}
|
|
||||||
return serviced;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hlw_commands(char *svalue, uint16_t ssvalue)
|
|
||||||
{
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"Commands5\":\"PowerLow, PowerHigh, VoltageLow, VoltageHigh, CurrentLow, CurrentHigh, HlwPcal, HlwUcal, HlwIcal%s\"}"),
|
|
||||||
(FEATURE_POWER_LIMIT)?", SafePower, SafePowerHold, SafePowerWindow, MaxPower, MaxPowerHold, MaxPowerWindow, MaxEnergy, MaxEnergyStart":"");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* Presentation
|
|
||||||
\*********************************************************************************************/
|
|
||||||
|
|
||||||
void hlw_mqttStat(byte option, char* svalue, uint16_t ssvalue)
|
|
||||||
{
|
|
||||||
char stemp0[10], stemp1[10], stemp2[10], stemp3[10], speriod[20];
|
|
||||||
float ped, pi, pc;
|
|
||||||
uint16_t pe, pw, pu;
|
|
||||||
|
|
||||||
hlw_readEnergy(option, 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(speriod, sizeof(speriod), PSTR(", \"Period\":%d"), pe);
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("%s\"Yesterday\":%s, \"Today\":%s%s, \"Power\":%d, \"Factor\":%s, \"Voltage\":%d, \"Current\":%s}"),
|
|
||||||
svalue, stemp0, stemp1, (option) ? speriod : "", pw, stemp2, pu, stemp3);
|
|
||||||
#ifdef USE_DOMOTICZ
|
|
||||||
dtostrf(ped * 1000, 1, 1, stemp1);
|
|
||||||
domoticz_sensor4(pw, stemp1);
|
|
||||||
#endif // USE_DOMOTICZ
|
|
||||||
}
|
|
||||||
|
|
||||||
void hlw_mqttPresent()
|
|
||||||
{
|
|
||||||
char svalue[MESSZ], stime[21];
|
|
||||||
|
|
||||||
snprintf_P(stime, sizeof(stime), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"),
|
|
||||||
rtcTime.Year, rtcTime.Month, rtcTime.Day, rtcTime.Hour, rtcTime.Minute, rtcTime.Second);
|
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\", "), stime);
|
|
||||||
hlw_mqttStat(1, svalue, sizeof(svalue));
|
|
||||||
|
|
||||||
// snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/ENERGY"), PUB_PREFIX2, sysCfg.mqtt_topic);
|
|
||||||
// mqtt_publish(stopic, svalue);
|
|
||||||
|
|
||||||
mqtt_publish_topic_P(1, PSTR("ENERGY"), svalue);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void hlw_mqttStatus(char* svalue, uint16_t ssvalue)
|
|
||||||
{
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("{\"StatusPWR\":{"));
|
|
||||||
hlw_mqttStat(0, svalue, ssvalue);
|
|
||||||
snprintf_P(svalue, ssvalue, PSTR("%s}"), svalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
@ -1,271 +0,0 @@
|
|||||||
/*
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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
Block a user