├── .github └── workflows │ ├── action.yml │ └── main.yml ├── .gitignore ├── .gitmodules ├── Connectors_Conrad.md ├── Connectors_RSO.md ├── HeatPumpType.md ├── HeishaMon ├── HeishaMon.ino ├── HeishaOT.cpp ├── HeishaOT.h ├── commands.cpp ├── commands.h ├── dallas.cpp ├── dallas.h ├── decode.cpp ├── decode.h ├── gpio.cpp ├── gpio.h ├── htmlcode.h ├── rules.cpp ├── rules.h ├── s0.cpp ├── s0.h ├── src │ ├── common │ │ ├── base64.cpp │ │ ├── base64.h │ │ ├── log.cpp │ │ ├── log.h │ │ ├── mem.cpp │ │ ├── mem.h │ │ ├── progmem.h │ │ ├── sha1.cpp │ │ ├── sha1.h │ │ ├── stricmp.cpp │ │ ├── stricmp.h │ │ ├── strncasestr.cpp │ │ ├── strncasestr.h │ │ ├── strnicmp.cpp │ │ ├── strnicmp.h │ │ ├── strnstr.cpp │ │ ├── strnstr.h │ │ ├── timerqueue.cpp │ │ ├── timerqueue.h │ │ ├── uint32float.cpp │ │ ├── uint32float.h │ │ ├── webserver.cpp │ │ └── webserver.h │ ├── opentherm │ │ ├── opentherm.cpp │ │ └── opentherm.h │ └── rules │ │ ├── function.cpp │ │ ├── function.h │ │ ├── functions │ │ ├── ceil.cpp │ │ ├── ceil.h │ │ ├── coalesce.cpp │ │ ├── coalesce.h │ │ ├── concat.cpp │ │ ├── concat.h │ │ ├── floor.cpp │ │ ├── floor.h │ │ ├── gpio.cpp │ │ ├── gpio.h │ │ ├── isset.cpp │ │ ├── isset.h │ │ ├── max.cpp │ │ ├── max.h │ │ ├── min.cpp │ │ ├── min.h │ │ ├── print.cpp │ │ ├── print.h │ │ ├── round.cpp │ │ ├── round.h │ │ ├── settimer.cpp │ │ └── settimer.h │ │ ├── operator.cpp │ │ ├── operator.h │ │ ├── rules.cpp │ │ ├── rules.h │ │ └── stack.h ├── version.h ├── webfunctions.cpp └── webfunctions.h ├── Heishamon-case-not-used-old-version.stl ├── Heishamon-case-small-version-with-opentherm.stl ├── Integrations ├── Domoticz │ ├── NodeRed │ │ └── NodeRed-Domoticz.json │ └── README.md ├── Home Assistant │ ├── README.md │ └── heishamon.yaml ├── Openhab2 │ ├── panasonic.items │ └── panasonic.sitemap ├── Openhab3 │ ├── README.md │ ├── aquareaHeatPump.yaml │ ├── aquarea_heatMode.map │ ├── aquarea_hiPowerMode.map │ ├── aquarea_holidayMode.map │ ├── aquarea_outletDirection.map │ └── aquarea_zonesActive.map └── ioBroker_manual │ ├── README.md │ └── images │ ├── adapters_mqtt.png │ ├── iobroker_objects.png │ ├── mqtt_setup.png │ └── sdc_values.png ├── LIBSUSED.md ├── MQTT-Topics.md ├── Manage-Topics.md ├── NewHeishamon.JPG ├── New_PCB.jpeg ├── OptionalPCB.md ├── PCB_Designs.md ├── Panasonic Aquarea-1677423314424.json ├── ProtocolByteDecrypt-extra.md ├── ProtocolByteDecrypt.md ├── README.md ├── README_DE.md ├── README_FI.md ├── README_NL.md ├── Tools └── chksumChecker.js ├── WEMOSD1.JPG ├── binaries ├── README.md ├── model-type-large │ ├── HeishaMon.ino.bootloader.bin │ ├── HeishaMon.ino.elf │ ├── HeishaMon.ino.esp32-v3.5.bin │ ├── HeishaMon.ino.esp32-v3.5.md5 │ ├── HeishaMon.ino.esp32-v3.6.bin │ ├── HeishaMon.ino.esp32-v3.6.md5 │ ├── HeishaMon.ino.esp32-v3.61.bin │ ├── HeishaMon.ino.esp32-v3.61.md5 │ ├── HeishaMon.ino.esp32-v3.62.bin │ ├── HeishaMon.ino.esp32-v3.62.md5 │ ├── HeishaMon.ino.esp32-v3.7.bin │ ├── HeishaMon.ino.esp32-v3.7.md5 │ ├── HeishaMon.ino.esp32-v3.8.bin │ ├── HeishaMon.ino.esp32-v3.8.complete.bin │ ├── HeishaMon.ino.esp32-v3.8.md5 │ ├── HeishaMon.ino.esp32-v3.9.bin │ ├── HeishaMon.ino.esp32-v3.9.md5 │ ├── HeishaMon.ino.map │ └── HeishaMon.ino.partitions.bin └── model-type-small │ ├── HeishaMon.ino.d1-v1.0.bin │ ├── HeishaMon.ino.d1-v1.0.md5 │ ├── HeishaMon.ino.d1-v2.0.bin │ ├── HeishaMon.ino.d1-v2.0.md5 │ ├── HeishaMon.ino.d1-v3.0.bin │ ├── HeishaMon.ino.d1-v3.0.md5 │ ├── HeishaMon.ino.d1-v3.1.bin │ ├── HeishaMon.ino.d1-v3.1.md5 │ ├── HeishaMon.ino.d1-v3.2.1.bin │ ├── HeishaMon.ino.d1-v3.2.1.md5 │ ├── HeishaMon.ino.d1-v3.2.2.bin │ ├── HeishaMon.ino.d1-v3.2.2.md5 │ ├── HeishaMon.ino.d1-v3.2.3.bin │ ├── HeishaMon.ino.d1-v3.2.3.md5 │ ├── HeishaMon.ino.d1-v3.2.4-beta-OTupdates.bin │ ├── HeishaMon.ino.d1-v3.2.4-beta.bin │ ├── HeishaMon.ino.d1-v3.2.bin │ ├── HeishaMon.ino.d1-v3.2.md5 │ ├── HeishaMon.ino.d1-v3.5.bin │ ├── HeishaMon.ino.d1-v3.5.md5 │ ├── HeishaMon.ino.d1-v3.6.bin │ ├── HeishaMon.ino.d1-v3.6.md5 │ ├── HeishaMon.ino.d1-v3.61.bin │ ├── HeishaMon.ino.d1-v3.61.md5 │ ├── HeishaMon.ino.d1-v3.62.bin │ ├── HeishaMon.ino.d1-v3.62.md5 │ ├── HeishaMon.ino.d1-v3.7.bin │ ├── HeishaMon.ino.d1-v3.7.md5 │ ├── HeishaMon.ino.d1-v3.8.bin │ ├── HeishaMon.ino.d1-v3.8.md5 │ ├── HeishaMon.ino.d1-v3.9.bin │ └── HeishaMon.ino.d1-v3.9.md5 ├── heatpump-internal-temperatures.png └── optional-long-distance-heishamon.png /.github/workflows/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | on: 3 | schedule: 4 | - cron: '30 1 * * *' 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v9 11 | with: 12 | stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.' 13 | days-before-stale: 30 14 | days-before-close: 5 -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build binary 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | ARDUINO_BOARD_MANAGER_ADDITIONAL_URLS: "http://arduino.esp8266.com/stable/package_esp8266com_index.json https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json" 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | 16 | - name: Update version.h 17 | if: github.ref != 'refs/heads/main' #do not change version in main branch run 18 | run: cd HeishaMon && echo "static const char *heishamon_version = \"Alpha-$(git rev-parse --short HEAD)\";" > version.h && cat version.h 19 | shell: bash 20 | 21 | - name: Setup Arduino CLI 22 | uses: arduino/setup-arduino-cli@v2 23 | 24 | - name: Install platform 25 | run: | 26 | arduino-cli core update-index 27 | arduino-cli core install esp8266:esp8266 28 | arduino-cli core install esp32:esp32@3.0.7 29 | 30 | - name: Install dependencies 31 | run: arduino-cli lib install ringbuffer pubsubclient arduinojson dallastemperature onewire "Adafruit NeoPixel" 32 | 33 | - name: Fix Onewire lib for ESP32-3.0.0 34 | run: | 35 | sed -i '/#include /a\ 36 | #include ' \ 37 | /home/runner/Arduino/libraries/OneWire/util/OneWire_direct_gpio.h 38 | 39 | - name: Compile Sketch for ESP8266 40 | run: cd HeishaMon && arduino-cli compile --output-dir . --fqbn=esp8266:esp8266:d1_mini:xtal=160,vt=flash,ssl=basic,mmu=3216,non32xfer=fast,eesz=4M2M,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=921600 --warnings=none --verbose HeishaMon.ino 41 | 42 | - name: Add MD5 checksum to ESP8266 binary 43 | run: cd HeishaMon && MD5=`md5sum HeishaMon.ino.bin | cut -d\ -f1` && mv HeishaMon.ino.bin HeishaMon_ESP8266-alpha-$MD5.bin 44 | shell: bash 45 | 46 | - name: Compile Sketch for ESP32 47 | run: cd HeishaMon && arduino-cli compile --output-dir . --fqbn=esp32:esp32:esp32s3:CDCOnBoot=cdc,PSRAM=enabled,PartitionScheme=min_spiffs --warnings=none --verbose HeishaMon.ino 48 | 49 | - name: Add MD5 checksum to ESP32 binary 50 | run: cd HeishaMon && MD5=`md5sum HeishaMon.ino.bin | cut -d\ -f1` && mv HeishaMon.ino.bin HeishaMon_ESP32-alpha-$MD5.bin 51 | shell: bash 52 | 53 | - name: Upload artifacts 54 | uses: actions/upload-artifact@v4 55 | with: 56 | name: HeishaMon.ino.bin 57 | path: HeishaMon/HeishaMon_*.bin 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | .vs 6 | .pio 7 | pio 8 | .vscode 9 | .pioenvs 10 | .cache 11 | build_output 12 | firmware.map 13 | firmware.asm -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Integrations/Domoticz/HeishamonMQTT"] 2 | path = Integrations/Domoticz/HeishamonMQTT 3 | url = https://github.com/MarFanNL/HeishamonMQTT 4 | [submodule "Integrations/NodeRed"] 5 | path = Integrations/NodeRed 6 | url = https://github.com/edterbak/NodeRed_Heishamon_control 7 | -------------------------------------------------------------------------------- /Connectors_Conrad.md: -------------------------------------------------------------------------------- 1 | ## For Conrad orders 2 | 3 | | JST Type | Conrad article number | Description | 4 | | ----- | ----: | ----- | 5 | |B05B-XASK-1| 741366 | Header matching CZ-TAW1, for soldering on PCB. S05B-XASK-1 (not orderable at conrad) is the side-ways version | 6 | |B05B-PASK-1| 1426194 | Header matching CN-CNT (that what is on the heatpump itself). Only need this if you want to build a proxy-forward PCB| 7 | |XAP-05V-1| 741233 | Cable connector on CZ-TAW1/PCB side | 8 | |PAP-05V-1| 1426227 | Cable connector on CN-CNT side | 9 | |BXA-01T-P0.6| 741295 |Connector pins on CZ-TAW1/PCB side| 10 | |SPHD-002T-P0.5| 1426240 | Connector pins on CN-CNT side | 11 | |PHR-4| 740614 | CN-NMode 4-pin connector housing | 12 | |SPH-002T-P0.5S| 741135 | CN-NMode connector pins | -------------------------------------------------------------------------------- /Connectors_RSO.md: -------------------------------------------------------------------------------- 1 | ## For RS-Online orders 2 | 3 | | JST Type | RS-Online article number | Description | 4 | | ----- | ---- | ----- | 5 | |CN-CNT female connector PAP-05V-S | [4766768](https://uk.rs-online.com/web/p/pcb-connector-housings/4766798/) | JST Female Connector Housing - PA, 2mm Pitch, 5 Way, 1 Row | 6 | |CZ-TAW1 male header JST B05B-XASK-1 | [6027679](https://uk.rs-online.com/web/p/pcb-headers/6027679/) | | 7 | |Pre-made crimp leads 150 mm | [5128726](https://uk.rs-online.com/web/p/pre-crimped-leads/5128721/)| crimp-free end lead PA 2.0 can be used | -------------------------------------------------------------------------------- /HeatPumpType.md: -------------------------------------------------------------------------------- 1 | ## HeatPumpType: 2 | 3 | Assuming that bytes from #129 to #138 are unique for each model of Aquarea heat pump: 4 | 5 | | Value | Bytes 129 - 138 | IDU | ODU | KIT | Power [kW] | 1ph/3ph | T-CAP/HP | 6 | | ---| --- | --- | --- | --- | --- | --- | ---| 7 | | 0 | E2 CF 0B 13 33 32 D1 0C 16 33 | Monoblock | WH-MDC05H3E5 | Monoblock | 5 | 1ph | HP | 8 | | 1 | E2 CF 0B 14 33 42 D1 0B 17 33 | Monoblock | WH-MDC07H3E5 | Monoblock | 7 | 1ph | HP | 9 | | 2 | E2 CF 0D 77 09 12 D0 0B 05 11 | WH-SXC09H3E5 | WH-UX09HE5 | KIT-WXC09H3E5 | 9 | 1ph | T-CAP | 10 | | 3 | E2 CF 0C 88 05 12 D0 0B 97 05 | WH-SDC09H3E8 | WH-UD09HE8 | KIT-WC09H3E8 | 9 | 3ph | HP | 11 | | 4 | E2 CF 0D 85 05 12 D0 0C 94 05 | WH-SXC09H3E8 | WH-UX09HE8 | KIT-WXC09H9E8 | 9 | 3ph | T-CAP | 12 | | 5 | E2 CF 0D 86 05 12 D0 0C 95 05 | WH-SXC12H9E8 | WH-UX12HE8 | KIT-WXC12H9E8 | 12 | 3ph | T-CAP | 13 | | 6 | E2 CF 0D 87 05 12 D0 0C 96 05 | WH-SXC16H9E8 | WH-UX16HE8 | KIT-WXC16H9E8 | 16 | 3ph | T-CAP | 14 | | 7 | E2 CE 0D 71 81 72 CE 0C 92 81 | WH-SDC05H3E5 | WH-UD05HE5 | KIT-WC05H3E5 | 5 | 1ph | HP | 15 | | 8 | 62 D2 0B 43 54 42 D2 0B 72 66 | WH-SDC0709J3E5 | WH-UD09JE5 | KIT-WC09J3E5 | 9 | 1ph | HP | 16 | | 9 | C2 D3 0B 33 65 B2 D3 0B 94 65 | Monoblock | WH-MDC05J3E5 | Monoblock | 5 | 1ph | HP | 17 | |10 | E2 CF 0B 15 33 42 D1 0B 18 33 | Monoblock | WH-MDC09H3E5 | Monoblock | 9 | 1ph | HP | 18 | |11 | E2 CF 0B 41 34 82 D1 0B 31 35 | Monoblock | WH-MXC09H3E5 | Monoblock | 9 | 1ph | T-CAP | 19 | |12 | 62 D2 0B 45 54 42 D2 0B 47 55 | WH-ADC0309J3E5 | WH-UD09JE5 | KIT-ADC09JE5 | 9 | 1ph | HP - All-In-One | 20 | |13 | E2 CF 0C 74 09 12 D0 0D 95 05 | WH-ADC0916H9E8 | WH-UX12HE8 | KIT-AXC12HE8 | 12 | 3ph | T-CAP - All-In-One | 21 | |14 | E2 CF 0B 82 05 12 D0 0C 91 05 | WH-SQC09H3E8 | WH-UQ09HE8 | KIT-WQC09H3E8 | 9 | 3ph | T-CAP - Super Quiet | 22 | |15 | E2 CF 0C 55 14 12 D0 0B 15 08 | WH-SDC09H3E5 | WH-UD09HE5 | KIT-WC09H3E5 | 9 | 1 ph | HP | 23 | |16 | E2 CF 0C 43 00 12 D0 0B 15 08 | WH-ADC0309H3E5 | WH-UD09HE5 | KIT-ADC09HE5 | 9 | 1 ph | HP - All-In-One | 24 | |17 | 62 D2 0B 45 54 32 D2 0C 45 55 | WH-ADC0309J3E5 | WH-UD05JE5 | KIT-ADC05JE5 | 5 | 1ph | HP - All-In-One | 25 | |18 | 62 D2 0B 43 54 42 D2 0C 46 55 | WH-SDC0709J3E5 | WH-UD07JE5 | KIT-WC07J3E5 | 7 | 1 ph | HP | 26 | |19 | E2 CF 0C 54 14 12 D0 0B 14 08 | WH-SDC07H3E5-1 | WH-UD07HE5-1 | KIT-WC07H3E5-1 | 7 | 1 ph | HP | 27 | |20 | C2 D3 0B 34 65 B2 D3 0B 95 65 | Monoblock | WH-MDC07J3E5 | Monoblock | 7 | 1ph | HP | 28 | |21 | C2 D3 0B 35 65 B2 D3 0B 96 65 | Monoblock | WH-MDC09J3E5 | Monoblock | 9 | 1ph | HP | 29 | |22 | 62 D2 0B 41 54 32 D2 0C 45 55 | WH-SDC0305J3E5 | WH-UD05JE5 | KIT-WC05J3E5 | 5 | 1ph | HP | 30 | |23 | 32 D4 0B 87 84 73 90 0C 84 84 | Monoblock | WH-MXC09J3E8 | Monoblock | 9 | 3ph | T-CAP | 31 | |24 | 32 D4 0B 88 84 73 90 0C 85 84 | Monoblock | WH-MXC12J9E8 | Monoblock | 12 | 3ph | T-CAP | 32 | |25 | E2 CF 0B 75 09 12 D0 0C 06 11 | WH-ADC1216H6E5 | WH-UD12HE5 | KIT-ADC12HE5 | 12 | 1ph | T-CAP | 33 | |26 | 42 D4 0B 83 71 42 D2 0C 46 55 | WH-ADC0309J3E5C | WH-UD07JE5 | KIT-ADC07JE5C | 7 | 1ph | HP - All-In-One Compact | 34 | |27 | C2 D3 0C 34 65 B2 D3 0B 95 65 | Monoblock | WH-MDC07J3E5 | Monoblock | 7 | 1ph | HP (new version) | 35 | |28 | C2 D3 0C 33 65 B2 D3 0B 94 65 | Monoblock | WH-MDC05J3E5 | Monoblock | 5 | 1ph | HP (new version) | 36 | |29 | E2 CF 0B 83 05 12 D0 0D 92 05 | WH-SQC12H9E8 | WH-UQ12HE8 | KIT-WQC12H9E8 | 12 | 3ph | T-CAP - Super Quiet | 37 | |30 | E2 CF 0C 78 09 12 D0 0B 06 11 | WH-SXC12H6E5 | WH-UX12HE5 | KIT-WXC12H6E5 | 12 | 1ph | T-CAP | 38 | |31 | C2 D3 0C 35 65 B2 D3 0B 96 65 | Monoblock | WH-MDC09J3E5 | Monoblock | 9 | 1ph | HP (new version?) | 39 | |32 | 32 D4 0B 99 77 62 90 0B 01 78 | Monoblock | WH-MXC09J3E5 | Monoblock | 9 | 1ph | T-CAP 40 | |33 | 42 D4 0B 15 76 12 D0 0B 10 11 | WH-ADC1216H6E5C | WH-UD12HE5 | KIT-ADC12HE5C-CL | 12 | 1ph| HP - All-In-One Compact | 41 | |34 | E2 D5 0C 29 99 83 92 0C 28 98 | WH-ADC0509L3E5 | WH-WDG07LE5 | KIT-ADC07L3E5 | 7 | 1ph | HP - All-In-One L-series | 42 | |35 | E2 CF 0D 85 05 12 D0 0E 94 05 | WH-SXC09H3E8 | WH-UX09HE8 | KIT-WXC09H3E8 | 9 | 3ph | T-CAP - new version | 43 | |36 | E2 D5 0D 36 99 02 D6 0F 67 95 | WH-ADC0309K3E5AN | WH-UDZ07KE5 | KIT-ADC07K3E5AN | 7 | 1ph | HP - All-In-One K-series - AN | 44 | |37 | E2 D5 0B 08 95 02 D6 0E 66 95 | WH-SDC0309K3E5 | WH-UDZ05KE5 | KIT-WC05K3E5 | 5 | 1ph | HP - split K-series | 45 | |38 | E2 D5 0B 34 99 83 92 0C 29 98 | WH-SDC0509L3E5 | WH-WDG09LE5 | KIT-WC09L3E5 | 9 | 1 ph | HP - split L-series 3kW elec heating | 46 | |39 | E2 CF 0C 89 05 12 D0 0C 98 05 | WH-SDC12H9E8 | WH-UD12HE8 | KIT-WC12H9E8 | 12 | 3ph | HP | 47 | |40 | E2 D5 0B 08 95 02 D6 0E 67 95 | WH-SDC0309K3E5 | WH-UDZ07KE5 | KIT-WC07K3E5 | 7 | 1ph | HP - split K-series | 48 | |41 | E2 CF 0C 74 09 12 D0 0C 96 05 | WH-ADC0916H9E8 | WH-UX16HE8 | KIT-AXC16HE8 | 16 | 3ph | T-CAP - All-In-One | 49 | |42 | E2 CF 0C 74 09 12 D0 0E 95 05 | WH-ADC0912H9E8 | WH-UX12HE8 | KIT-AXC12HE8 | 12 | 3ph | T-CAP - All-In-One | 50 | |43 | 32 D4 0B 89 84 73 90 0C 86 84 | Monoblock | WH-MXC16J9E8 | Monoblock | 16 | 3ph | T-CAP | 51 | |44 | 32 D4 0B 00 78 62 90 0B 02 78 | Monoblock | WH-MXC12J6E5 | Monoblock | 12 | 1ph | T-CAP | 52 | |45 | E2 CF 0B 82 05 12 D0 0D 91 05 | WH-SQC09H3E8 | WH-UQ09HE8 | KIT-WQC09H3E8 | 9 | 3ph | T-CAP - Super Quiet revised model | 53 | |46 | E2 D5 0D 99 94 02 D6 0D 68 95 | WH-ADC0309K3E5 | WH-UDZ09KE5 | KIT-ADC09K3E5 | 9 | 1ph | HP - K-series All-in-One R32 | 54 | |47 | E2 CF 0C 74 09 12 D0 0C 95 05 | WH-ADC0916H9E8 | WH-UX12HE8 | KIT-AXC12HE8 | 12 | 3ph | T-CAP - All-In-One | 55 | |48 | E2 D5 0B 34 99 83 92 0C 28 98 | WH-SDC0509L3E5 | WH-WDG07LE5 | KIT-WC07L3E5 | 7 | 1 ph | HP - split L-series 3kW elec heating | 56 | |49 | E2 CF 0D 77 09 12 D0 0C 05 11 | WH-SXC09H3E5 | WH-UX09HE5 | KIT-WXC09H3E5 | 9 | 1ph | T-CAP | 57 | |50 | E2 CF 0B 44 34 12 D0 0C 34 35 | Monoblock | WH-MXC12H9E8 | Monoblock | 12 | 3ph | T-CAP | 58 | |51 | E2 D5 0C 67 00 83 92 0C 27 98 | WH-ADC0509L3E5AN | WH-WDG05LE5 | KIT-ADC05L3E5AN | 5 | 1ph | HP - split L-series 3kW elec heating - AN | 59 | |52 | E2 D5 0B 34 99 83 92 0C 27 98 | WH-SDC0509L3E5 | WH-WDG05LE5 | KIT-WC05L3E5 | 5 | 1ph | HP - split L-series 3kW elec heating | 60 | |53 | 42 D4 0B 83 71 32 D2 0C 44 55 | WH-ADC0309J3E5C | WH-UD03JE5 | KIT-ADC03JE5C-S | 3.2 | 1ph | HP - All-In-One Compact | 61 | |54 | E2 CF 0C 74 09 12 D0 0E 94 05 | WH-ADC0916H9E8 | WH-UX09HE8 | KIT-AXC9HE8 | 9 | 3ph | T-CAP - All-In-One | 62 | 63 | All bytes are used for Heat Pump model identification in the code. 64 | 65 | Note: These are the heat pump types that users have verified and reported back the model. HeishaMon should work with all H and J generation Aquarea heat pumps. 66 | -------------------------------------------------------------------------------- /HeishaMon/HeishaOT.h: -------------------------------------------------------------------------------- 1 | #ifndef _HEISHA_OT_H_ 2 | #define _HEISHA_OT_H_ 3 | 4 | #include 5 | #include "src/common/webserver.h" 6 | 7 | // opentherm 8 | #if defined(ESP8266) 9 | #define inOTPin 3 //RX pin from ESP8266 10 | #define outOTPin 1 //TX pin from ESP8266 11 | #elif defined(ESP32) 12 | #define inOTPin 6 13 | #define outOTPin 7 14 | #endif 15 | 16 | // mqtt 17 | extern const char* mqtt_topic_opentherm_read; 18 | extern const char* mqtt_topic_opentherm_write; 19 | 20 | 21 | #define TBOOL 1 22 | #define TFLOAT 2 23 | #define TINT8 3 24 | 25 | typedef struct heishaOTDataStruct_t { 26 | const char *name; 27 | uint8_t type; 28 | union { 29 | bool b; 30 | float f; 31 | int8_t s8; 32 | } value; 33 | uint8_t rw; 34 | } heishaOTDataStruct_t; 35 | 36 | extern struct heishaOTDataStruct_t heishaOTDataStruct[]; 37 | 38 | void HeishaOTSetup(); 39 | void HeishaOTLoop(char *actDat, PubSubClient &mqtt_client, char* mqtt_topic_base); 40 | void mqttOTCallback(char* topic, char* value); 41 | void openthermJsonOutput(struct webserver_t *client); 42 | 43 | #endif -------------------------------------------------------------------------------- /HeishaMon/commands.h: -------------------------------------------------------------------------------- 1 | #define LWIP_INTERNAL 2 | 3 | #include 4 | 5 | #define DATASIZE 203 6 | 7 | #define INITIALQUERYSIZE 7 8 | extern byte initialQuery[INITIALQUERYSIZE]; 9 | #define PANASONICQUERYSIZE 110 10 | extern byte panasonicQuery[PANASONICQUERYSIZE]; 11 | 12 | 13 | #define OPTDATASIZE 20 14 | #define OPTIONALPCBQUERYTIME 1000 //send optional pcb query each second 15 | #define OPTIONALPCBQUERYSIZE 19 16 | #define OPTIONALPCBSAVETIME 300 //save each 5 minutes the current optional pcb state into flash to have valid values during reboot 17 | extern byte optionalPCBQuery[OPTIONALPCBQUERYSIZE]; 18 | 19 | 20 | extern const char* mqtt_topic_values; 21 | extern const char* mqtt_topic_xvalues; 22 | extern const char* mqtt_topic_commands; 23 | extern const char* mqtt_topic_pcbvalues; 24 | extern const char* mqtt_topic_1wire; 25 | extern const char* mqtt_topic_s0; 26 | extern const char* mqtt_topic_pcb; 27 | extern const char* mqtt_logtopic; 28 | extern const char* mqtt_willtopic; 29 | extern const char* mqtt_iptopic; 30 | extern const char* mqtt_send_raw_value_topic; 31 | 32 | unsigned int set_heatpump_state(char *msg, unsigned char *cmd, char *log_msg); 33 | unsigned int set_pump(char *msg, unsigned char *cmd, char *log_msg); 34 | unsigned int set_max_pump_duty(char *msg, unsigned char *cmd, char *log_msg); 35 | unsigned int set_quiet_mode(char *msg, unsigned char *cmd, char *log_msg); 36 | unsigned int set_z1_heat_request_temperature(char *msg, unsigned char *cmd, char *log_msg); 37 | unsigned int set_z1_cool_request_temperature(char *msg, unsigned char *cmd, char *log_msg); 38 | unsigned int set_z2_heat_request_temperature(char *msg, unsigned char *cmd, char *log_msg); 39 | unsigned int set_z2_cool_request_temperature(char *msg, unsigned char *cmd, char *log_msg); 40 | unsigned int set_force_DHW(char *msg, unsigned char *cmd, char *log_msg); 41 | unsigned int set_force_defrost(char *msg, unsigned char *cmd, char *log_msg); 42 | unsigned int set_force_sterilization(char *msg, unsigned char *cmd, char *log_msg); 43 | unsigned int set_holiday_mode(char *msg, unsigned char *cmd, char *log_msg); 44 | unsigned int set_powerful_mode(char *msg, unsigned char *cmd, char *log_msg); 45 | unsigned int set_operation_mode(char *msg, unsigned char *cmd, char *log_msg); 46 | unsigned int set_DHW_temp(char *msg, unsigned char *cmd, char *log_msg); 47 | unsigned int set_curves(char *msg, unsigned char *cmd, char *log_msg); 48 | unsigned int set_zones(char *msg, unsigned char *cmd, char *log_msg); 49 | unsigned int set_floor_heat_delta(char *msg, unsigned char *cmd, char *log_msg); 50 | unsigned int set_floor_cool_delta(char *msg, unsigned char *cmd, char *log_msg); 51 | unsigned int set_dhw_heat_delta(char *msg, unsigned char *cmd, char *log_msg); 52 | unsigned int set_reset(char *msg, unsigned char *cmd, char *log_msg); 53 | unsigned int set_heater_delay_time(char *msg, unsigned char *cmd, char *log_msg); 54 | unsigned int set_heater_start_delta(char *msg, unsigned char *cmd, char *log_msg); 55 | unsigned int set_heater_stop_delta(char *msg, unsigned char *cmd, char *log_msg); 56 | unsigned int set_main_schedule(char *msg, unsigned char *cmd, char *log_msg); 57 | unsigned int set_alt_external_sensor(char *msg, unsigned char *cmd, char *log_msg); 58 | unsigned int set_external_pad_heater(char *msg, unsigned char *cmd, char *log_msg); 59 | unsigned int set_buffer_delta(char *msg, unsigned char *cmd, char *log_msg); 60 | unsigned int set_buffer(char *msg, unsigned char *cmd, char *log_msg); 61 | unsigned int set_heatingoffoutdoortemp(char *msg, unsigned char *cmd, char *log_msg); 62 | unsigned int set_bivalent_control(char *msg, unsigned char *cmd, char *log_msg); 63 | unsigned int set_bivalent_mode(char *msg, unsigned char *cmd, char *log_msg); 64 | unsigned int set_bivalent_start_temp(char *msg, unsigned char *cmd, char *log_msg); 65 | unsigned int set_bivalent_ap_start_temp(char *msg, unsigned char *cmd, char *log_msg); 66 | unsigned int set_bivalent_ap_stop_temp(char *msg, unsigned char *cmd, char *log_msg); 67 | unsigned int set_external_control(char *msg, unsigned char *cmd, char *log_msg); 68 | unsigned int set_external_error(char *msg, unsigned char *cmd, char *log_msg); 69 | 70 | //optional pcb commands 71 | unsigned int set_heat_cool_mode(char *msg, char *log_msg); 72 | unsigned int set_compressor_state(char *msg, char *log_msg); 73 | unsigned int set_smart_grid_mode(char *msg, char *log_msg); 74 | unsigned int set_external_thermostat_1_state(char *msg, char *log_msg); 75 | unsigned int set_external_thermostat_2_state(char *msg, char *log_msg); 76 | unsigned int set_demand_control(char *msg, char *log_msg); 77 | unsigned int set_pool_temp(char *msg, char *log_msg); 78 | unsigned int set_buffer_temp(char *msg, char *log_msg); 79 | unsigned int set_z1_room_temp(char *msg, char *log_msg); 80 | unsigned int set_z1_water_temp(char *msg, char *log_msg); 81 | unsigned int set_z2_room_temp(char *msg, char *log_msg); 82 | unsigned int set_z2_water_temp(char *msg, char *log_msg); 83 | unsigned int set_solar_temp(char *msg, char *log_msg); 84 | unsigned int set_byte_9(char *msg, char *log_msg); 85 | unsigned int set_external_compressor_control(char *msg, unsigned char *cmd, char *log_msg); 86 | unsigned int set_external_heat_cool_control(char *msg, unsigned char *cmd, char *log_msg); 87 | 88 | struct cmdStruct { 89 | char name[29]; 90 | unsigned int (*func)(char *msg, unsigned char *cmd, char *log_msg); 91 | }; 92 | 93 | const cmdStruct commands[] PROGMEM = { 94 | // set heatpump state to on by sending 1 95 | { "SetHeatpump", set_heatpump_state }, 96 | // set pump state to on by sending 1 97 | { "SetPump", set_pump }, 98 | // set max pump duty 99 | { "SetMaxPumpDuty", set_max_pump_duty }, 100 | // set 0 for Off mode, set 1 for Quiet mode 1, set 2 for Quiet mode 2, set 3 for Quiet mode 3 101 | { "SetQuietMode", set_quiet_mode }, 102 | // z1 heat request temp - set from -5 to 5 to get same temperature shift point or set direct temp 103 | { "SetZ1HeatRequestTemperature", set_z1_heat_request_temperature }, 104 | // z1 cool request temp - set from -5 to 5 to get same temperature shift point or set direct temp 105 | { "SetZ1CoolRequestTemperature", set_z1_cool_request_temperature }, 106 | // z2 heat request temp - set from -5 to 5 to get same temperature shift point or set direct temp 107 | { "SetZ2HeatRequestTemperature", set_z2_heat_request_temperature }, 108 | // z2 cool request temp - set from -5 to 5 to get same temperature shift point or set direct temp 109 | { "SetZ2CoolRequestTemperature", set_z2_cool_request_temperature }, 110 | // set mode to force DHW by sending 1 111 | { "SetForceDHW", set_force_DHW }, 112 | // set mode to force defrost by sending 1 113 | { "SetForceDefrost", set_force_defrost }, 114 | // set mode to force sterilization by sending 1 115 | { "SetForceSterilization", set_force_sterilization }, 116 | // set Holiday mode by sending 1, off will be 0 117 | { "SetHolidayMode", set_holiday_mode }, 118 | // set Powerful mode by sending 0 = off, 1 for 30min, 2 for 60min, 3 for 90 min 119 | { "SetPowerfulMode", set_powerful_mode }, 120 | // set Heat pump operation mode 3 = DHW only, 0 = heat only, 1 = cool only, 2 = Auto, 4 = Heat+DHW, 5 = Cool+DHW, 6 = Auto + DHW 121 | { "SetOperationMode", set_operation_mode }, 122 | // set DHW temperature by sending desired temperature between 40C-75C 123 | { "SetDHWTemp", set_DHW_temp }, 124 | // set heat/cool curves on z1 and z2 using a json input 125 | { "SetCurves", set_curves }, 126 | // set zones to active 127 | { "SetZones", set_zones }, 128 | { "SetFloorHeatDelta", set_floor_heat_delta }, 129 | { "SetFloorCoolDelta", set_floor_cool_delta }, 130 | { "SetDHWHeatDelta", set_dhw_heat_delta }, 131 | { "SetReset", set_reset }, 132 | { "SetHeaterDelayTime", set_heater_delay_time }, 133 | { "SetHeaterStartDelta", set_heater_start_delta }, 134 | { "SetHeaterStopDelta", set_heater_stop_delta }, 135 | { "SetMainSchedule", set_main_schedule }, 136 | { "SetAltExternalSensor", set_alt_external_sensor }, 137 | { "SetExternalPadHeater", set_external_pad_heater }, 138 | { "SetBufferDelta", set_buffer_delta }, 139 | { "SetBuffer", set_buffer }, 140 | // set Outdoor Temperature to stop heating 5-35 141 | { "SetHeatingOffOutdoorTemp", set_heatingoffoutdoortemp }, 142 | { "SetExternalControl", set_external_control }, 143 | { "SetExternalError", set_external_error }, 144 | { "SetExternalCompressorControl", set_external_compressor_control }, 145 | { "SetExternalHeatCoolControl", set_external_heat_cool_control }, 146 | // set Bivalent control mode 0 = off, 1 = on 147 | { "SetBivalentControl", set_bivalent_control }, 148 | // set Bivalent operation mode 0 = Alternativ, 1 = Parallel, 2 = Advanced Parallel 149 | { "SetBivalentMode", set_bivalent_mode }, 150 | // bivalent start temp - set from -15C to 35C 151 | { "SetBivalentStartTemp", set_bivalent_start_temp }, 152 | // bivalent AP start temp - set from -15C to 35C 153 | { "SetBivalentAPStartTemp", set_bivalent_ap_start_temp }, 154 | // bivalent AP stop temp - set from -15C to 35C 155 | { "SetBivalentAPStopTemp", set_bivalent_ap_stop_temp }, 156 | }; 157 | 158 | struct optCmdStruct{ 159 | char name[28]; 160 | unsigned int (*func)(char *msg, char *log_msg); 161 | }; 162 | 163 | const optCmdStruct optionalCommands[] PROGMEM = { 164 | // optional PCB 165 | { "SetHeatCoolMode", set_heat_cool_mode }, 166 | { "SetCompressorState", set_compressor_state }, 167 | { "SetSmartGridMode", set_smart_grid_mode }, 168 | { "SetExternalThermostat1State", set_external_thermostat_1_state }, 169 | { "SetExternalThermostat2State", set_external_thermostat_2_state }, 170 | { "SetDemandControl", set_demand_control }, 171 | { "SetPoolTemp", set_pool_temp }, 172 | { "SetBufferTemp", set_buffer_temp }, 173 | { "SetZ1RoomTemp", set_z1_room_temp }, 174 | { "SetZ1WaterTemp", set_z1_water_temp }, 175 | { "SetZ2RoomTemp", set_z2_room_temp }, 176 | { "SetZ2WaterTemp", set_z2_water_temp }, 177 | { "SetSolarTemp", set_solar_temp }, 178 | { "SetOptPCBByte9", set_byte_9 } 179 | }; 180 | 181 | void send_heatpump_command(char* topic, char *msg, bool (*send_command)(byte*, int), void (*log_message)(char*), bool optionalPCB); 182 | bool saveOptionalPCB(byte* command, int length); 183 | bool loadOptionalPCB(byte* command, int length); 184 | -------------------------------------------------------------------------------- /HeishaMon/dallas.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "commands.h" 5 | #include "dallas.h" 6 | #include "rules.h" 7 | #include "src/common/progmem.h" 8 | #include 9 | #include 10 | 11 | #define MQTT_RETAIN_VALUES 1 // do we retain 1wire values? 12 | 13 | #define MAXTEMPDIFFPERSEC 0.5 // what is the allowed temp difference per second which is allowed (to filter bad values) 14 | 15 | #define DALLASASYNC 1 //async dallas yes or no (default yes) 16 | 17 | OneWire oneWire(ONE_WIRE_BUS); 18 | DallasTemperature DS18B20(&oneWire); 19 | 20 | //global array for 1wire data 21 | dallasDataStruct* actDallasData = 0; 22 | int dallasDevicecount = 0; 23 | 24 | 25 | unsigned long lastalldatatime_dallas = 0; 26 | 27 | unsigned long dallasTimer = 0; 28 | unsigned long dallasTimer1 = 0; 29 | unsigned int updateAllDallasTime = 30000; // will be set using heishmonSettings 30 | unsigned int dallasTimerWait = 30000; // will be set using heishmonSettings 31 | void loadDallasAlias(); 32 | 33 | void initDallasSensors(void (*log_message)(char*), unsigned int updateAllDallasTimeSettings, unsigned int dallasTimerWaitSettings, unsigned int dallasResolution) { 34 | char log_msg[256]; 35 | updateAllDallasTime = updateAllDallasTimeSettings; 36 | dallasTimerWait = dallasTimerWaitSettings; 37 | DS18B20.begin(); 38 | dallasDevicecount = DS18B20.getDeviceCount(); 39 | sprintf_P(log_msg, PSTR("Number of 1wire sensors on bus: %d"), dallasDevicecount); log_message(log_msg); 40 | if ( dallasDevicecount > MAX_DALLAS_SENSORS) { 41 | dallasDevicecount = MAX_DALLAS_SENSORS; 42 | sprintf_P(log_msg, PSTR("Reached max 1wire sensor count. Only %d sensors will provide data."), dallasDevicecount); 43 | log_message(log_msg); 44 | } 45 | 46 | //init array 47 | delete actDallasData; 48 | actDallasData = new dallasDataStruct [dallasDevicecount]; 49 | for (int j = 0 ; j < dallasDevicecount; j++) { 50 | DS18B20.getAddress(actDallasData[j].sensor, j); 51 | DS18B20.setResolution(actDallasData[j].sensor, dallasResolution); 52 | } 53 | 54 | DS18B20.requestTemperatures(); 55 | for (int i = 0 ; i < dallasDevicecount; i++) { 56 | actDallasData[i].address[16] = '\0'; 57 | for (int x = 0; x < 8; x++) { 58 | // zero pad the address if necessary 59 | sprintf(&actDallasData[i].address[x * 2], "%02x", actDallasData[i].sensor[x]); 60 | } 61 | sprintf_P(log_msg, PSTR("Found 1wire sensor: %s"), actDallasData[i].address ); log_message(log_msg); 62 | } 63 | if (DALLASASYNC) DS18B20.setWaitForConversion(false); //async 1wire during next loops 64 | loadDallasAlias(); 65 | } 66 | 67 | void resetlastalldatatime_dallas() { 68 | lastalldatatime_dallas = 0; 69 | } 70 | 71 | void readNewDallasTemp(PubSubClient &mqtt_client, void (*log_message)(char*), char* mqtt_topic_base) { 72 | char log_msg[256]; 73 | char mqtt_topic[256]; 74 | char valueStr[80]; 75 | bool updatenow = false; 76 | 77 | if ((lastalldatatime_dallas == 0) || ((unsigned long)(millis() - lastalldatatime_dallas) > (1000 * updateAllDallasTime))) { 78 | updatenow = true; 79 | lastalldatatime_dallas = millis(); 80 | } 81 | if (!(DALLASASYNC)) DS18B20.requestTemperatures(); 82 | for (int i = 0; i < dallasDevicecount; i++) { 83 | float temp = DS18B20.getTempC(actDallasData[i].sensor); 84 | if (temp < -120.0) { 85 | sprintf_P(log_msg, PSTR("Error 1wire sensor offline: %s"), actDallasData[i].address); log_message(log_msg); 86 | } else { 87 | float allowedtempdiff = (((millis() - actDallasData[i].lastgoodtime)) / 1000.0) * MAXTEMPDIFFPERSEC; 88 | if ((actDallasData[i].temperature != -127.0) and ((temp > (actDallasData[i].temperature + allowedtempdiff)) or (temp < (actDallasData[i].temperature - allowedtempdiff)))) { 89 | sprintf_P(log_msg, PSTR("Filtering 1wire sensor temperature (%s). Delta to high. Current: %.2f Last: %.2f"), actDallasData[i].address, temp, actDallasData[i].temperature); 90 | log_message(log_msg); 91 | } else { 92 | actDallasData[i].lastgoodtime = millis(); 93 | if ((updatenow) || (actDallasData[i].temperature != temp )) { //only update mqtt topic if temp changed or after each update timer 94 | actDallasData[i].temperature = temp; 95 | sprintf(log_msg, PSTR("Received 1wire sensor temperature (%s): %.2f"), actDallasData[i].address, actDallasData[i].temperature); 96 | log_message(log_msg); 97 | if (true) { 98 | sprintf_P(valueStr, PSTR("%.2f"), actDallasData[i].temperature); 99 | sprintf_P(mqtt_topic, PSTR("%s/%s/%s"), mqtt_topic_base, mqtt_topic_1wire, actDallasData[i].address); mqtt_client.publish(mqtt_topic, valueStr, MQTT_RETAIN_VALUES); 100 | sprintf_P(valueStr, PSTR("%s"), actDallasData[i].alias); 101 | sprintf_P(mqtt_topic, PSTR("%s/%s/%s/alias"), mqtt_topic_base, mqtt_topic_1wire, actDallasData[i].address); mqtt_client.publish(mqtt_topic, valueStr, MQTT_RETAIN_VALUES); 102 | } else { 103 | sprintf_P(valueStr, PSTR("{\"Temperature\":%.2f,\"Alias\":\"%s\"}"), actDallasData[i].temperature, actDallasData[i].alias); 104 | sprintf_P(mqtt_topic, PSTR("%s/%s/%s"), mqtt_topic_base, mqtt_topic_1wire, actDallasData[i].address); mqtt_client.publish(mqtt_topic, valueStr, MQTT_RETAIN_VALUES); 105 | } 106 | sprintf_P(log_msg, PSTR("{\"data\": {\"dallasvalues\": {\"sensorID\": \"%s\", \"value\": %.2f}}}"), actDallasData[i].address, actDallasData[i].temperature); 107 | websocket_write_all(log_msg, strlen(log_msg)); 108 | rules_event_cb(_F("ds18b20#"), actDallasData[i].address); 109 | } 110 | } 111 | } 112 | } 113 | } 114 | 115 | void dallasLoop(PubSubClient &mqtt_client, void (*log_message)(char*), char* mqtt_topic_base) { 116 | if ((unsigned long)(millis() - dallasTimer) > (1000 * dallasTimerWait)) { 117 | log_message((char*)"Requesting new 1wire temperatures"); 118 | dallasTimer = millis(); 119 | if (DALLASASYNC){ 120 | DS18B20.requestTemperatures(); 121 | dallasTimer1=millis(); 122 | }else{ 123 | readNewDallasTemp(mqtt_client, log_message, mqtt_topic_base); 124 | } 125 | } 126 | if ((dallasTimer1!=0) && ((millis() - dallasTimer1)>750)){ 127 | dallasTimer1=0; 128 | readNewDallasTemp(mqtt_client, log_message, mqtt_topic_base); 129 | } 130 | } 131 | 132 | void dallasJsonOutput(struct webserver_t *client) { 133 | webserver_send_content_P(client, PSTR("["), 1); 134 | 135 | for (int i = 0; i < dallasDevicecount; i++) { 136 | webserver_send_content_P(client, PSTR("{\"Sensor\":\""), 11); 137 | webserver_send_content(client, actDallasData[i].address, strlen(actDallasData[i].address)); 138 | webserver_send_content_P(client, PSTR("\",\"Temperature\":"), 16); 139 | char str[64]; 140 | dtostrf(actDallasData[i].temperature, 0, 2, str); 141 | webserver_send_content(client, str, strlen(str)); 142 | webserver_send_content_P(client, PSTR(",\"Alias\":\""), 10); 143 | webserver_send_content(client, actDallasData[i].alias, strlen(actDallasData[i].alias)); 144 | if (i < dallasDevicecount - 1) { 145 | webserver_send_content_P(client, PSTR("\"},"), 3); 146 | } else { 147 | webserver_send_content_P(client, PSTR("\"}"), 2); 148 | } 149 | } 150 | webserver_send_content_P(client, PSTR("]"), 1); 151 | } 152 | 153 | void changeDallasAlias(char* address, char* alias) { 154 | JsonDocument jsonDoc; 155 | for (int i = 0 ; i < dallasDevicecount; i++) { 156 | if (strcmp(address, actDallasData[i].address) == 0) { 157 | strlcpy(actDallasData[i].alias, alias, sizeof(actDallasData[i].alias)); 158 | } 159 | jsonDoc[actDallasData[i].address] = actDallasData[i].alias; 160 | } 161 | if (LittleFS.begin()) { 162 | File configFile = LittleFS.open("/dallas.json", "w"); 163 | if (configFile) { 164 | serializeJson(jsonDoc, configFile); 165 | configFile.close(); 166 | } 167 | } 168 | } 169 | 170 | void loadDallasAlias() { 171 | if (LittleFS.begin()) { 172 | if (LittleFS.exists("/dallas.json")) { 173 | File configFile = LittleFS.open("/dallas.json", "r"); 174 | if (configFile) { 175 | size_t size = configFile.size(); 176 | std::unique_ptr buf(new char[size]); 177 | configFile.readBytes(buf.get(), size); 178 | JsonDocument jsonDoc; 179 | DeserializationError error = deserializeJson(jsonDoc, buf.get()); 180 | if (!error) { 181 | for (int i = 0 ; i < dallasDevicecount; i++) { 182 | if ( jsonDoc[actDallasData[i].address] ) strncpy(actDallasData[i].alias, jsonDoc[actDallasData[i].address], sizeof(actDallasData[i].alias)); 183 | } 184 | } 185 | } 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /HeishaMon/dallas.h: -------------------------------------------------------------------------------- 1 | #ifndef _DALLAS_H_ 2 | #define _DALLAS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "src/common/webserver.h" 8 | 9 | #define MAX_DALLAS_SENSORS 15 10 | #if defined(ESP8266) 11 | #define ONE_WIRE_BUS 4 12 | #elif defined(ESP32) 13 | #define ONE_WIRE_BUS 3 14 | #endif 15 | 16 | struct dallasDataStruct { 17 | float temperature = -127.0; 18 | unsigned long lastgoodtime = 0; 19 | DeviceAddress sensor; 20 | char address[17]; 21 | char alias[32] = "NOT SET"; 22 | }; 23 | 24 | void resetlastalldatatime_dallas(); 25 | void dallasLoop(PubSubClient &mqtt_client, void (*log_message)(char*), char* mqtt_topic_base); 26 | void initDallasSensors(void (*log_message)(char*), unsigned int updataAllDallasTimeSettings, unsigned int dallasTimerWaitSettings, unsigned int dallasResolution); 27 | void dallasJsonOutput(struct webserver_t *client); 28 | void changeDallasAlias(char* address, char* alias); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /HeishaMon/gpio.cpp: -------------------------------------------------------------------------------- 1 | #include "gpio.h" 2 | #include "src/common/progmem.h" 3 | #include "src/common/stricmp.h" 4 | const char* mqtt_topic_gpio PROGMEM = "gpio"; 5 | 6 | void log_message(char* string); 7 | 8 | void setupGPIO(gpioSettingsStruct gpioSettings) { 9 | for (int i = 0 ; i < NUMGPIO ; i++) { 10 | pinMode(gpioSettings.gpioPin[i], gpioSettings.gpioMode[i]); 11 | } 12 | } 13 | 14 | void mqttGPIOCallback(char* topic, char* value) { 15 | log_message(_F("GPIO: MQTT message received")); 16 | #ifdef ESP32 17 | if (strcmp_P(PSTR("relay/one"), topic) == 0) { 18 | log_message(_F("GPIO: MQTT message received 'relay/one'")); 19 | digitalWrite(relayOnePin,((stricmp((char*)"true", value) == 0) || (stricmp((char*)"on", value) == 0) || (stricmp((char*)"enable", value) == 0)|| (String(value).toInt() == 1 ))); 20 | } else if (strcmp_P(PSTR("relay/two"), topic) == 0) { 21 | log_message(_F("GPIO: MQTT message received 'relay/two'")); 22 | digitalWrite(relayTwoPin,((stricmp((char*)"true", value) == 0) || (stricmp((char*)"on", value) == 0) || (stricmp((char*)"enable", value) == 0)|| (String(value).toInt() == 1 ))); 23 | } 24 | #endif 25 | } -------------------------------------------------------------------------------- /HeishaMon/gpio.h: -------------------------------------------------------------------------------- 1 | #if defined(ESP8266) 2 | #define NUMGPIO 3 3 | #include 4 | #include 5 | #elif defined(ESP32) 6 | #define NUMGPIO 7 7 | #include 8 | #include 9 | #include 10 | #define relayOnePin 21 11 | #define relayTwoPin 47 12 | #endif 13 | 14 | extern const char* mqtt_topic_gpio; 15 | 16 | struct gpioSettingsStruct { 17 | #if defined(ESP8266) 18 | unsigned int gpioPin[NUMGPIO] = {1, 3, 16}; 19 | unsigned int gpioMode[NUMGPIO] = {INPUT_PULLUP, INPUT_PULLUP, INPUT_PULLUP}; 20 | #elif defined(ESP32) 21 | unsigned int gpioPin[NUMGPIO] = {33, 34, 35, 36, 37, 21, 47}; 22 | unsigned int gpioMode[NUMGPIO] = {INPUT_PULLUP, INPUT_PULLUP, INPUT_PULLUP, INPUT_PULLUP, INPUT_PULLUP, OUTPUT, OUTPUT}; 23 | #endif 24 | }; 25 | 26 | void setupGPIO(gpioSettingsStruct gpioSettings); 27 | void mqttGPIOCallback(char* topic, char* value); 28 | 29 | 30 | -------------------------------------------------------------------------------- /HeishaMon/rules.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef __RULES_H_ 10 | #define __RULES_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include "src/common/mem.h" 19 | 20 | extern uint8_t nrrules; 21 | 22 | void rules_boot(void); 23 | void rules_deinitialize(void); 24 | int rules_parse(char *file); 25 | void rules_setup(void); 26 | void rules_timer_cb(int nr); 27 | void rules_event_cb(const char *prefix, const char *name); 28 | void rules_execute(void); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /HeishaMon/s0.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "commands.h" 3 | #include "s0.h" 4 | 5 | #define MQTT_RETAIN_VALUES 1 // do we retain 1wire values? 6 | 7 | #define MINREPORTEDS0TIME 5000 // how often s0 Watts are reported (not faster than this) 8 | 9 | //global array for s0 data 10 | volatile s0DataStruct actS0Data[NUM_S0_COUNTERS]; 11 | 12 | //global array for s0 Settings 13 | volatile s0SettingsStruct actS0Settings[NUM_S0_COUNTERS]; 14 | 15 | 16 | //These are the interrupt routines. Make them as short as possible so we don't block main code 17 | volatile unsigned long lastEdgeS0[NUM_S0_COUNTERS] = {0, 0}; 18 | volatile bool badEdge[NUM_S0_COUNTERS] = {0, 0}; //two edges is a pulse, so store as bool 19 | 20 | //for debug 21 | /* 22 | volatile unsigned long allLastEdgeS0[2][20]; 23 | volatile int allLastEdgeS0Index[2] = {0, 0}; 24 | */ 25 | 26 | IRAM_ATTR void countPulse(int i) { 27 | volatile unsigned long newEdgeS0 = millis(); 28 | volatile unsigned long curPulseWidth = newEdgeS0 - lastEdgeS0[i]; 29 | // debug 30 | /* 31 | if (allLastEdgeS0Index[i] < 20) { 32 | allLastEdgeS0[i][allLastEdgeS0Index[i]] = curPulseWidth; 33 | allLastEdgeS0Index[i]++; 34 | } 35 | */ 36 | // end debug 37 | if ((curPulseWidth >= actS0Settings[i].minimalPulseWidth) && (curPulseWidth <= actS0Settings[i].maximalPulseWidth) ) { 38 | if (actS0Data[i].lastPulse > 0) { //Do not calculate watt for the first pulse since reboot because we will always report a too high watt. Better to show 0 watt at first pulse. 39 | volatile unsigned long pulseInterval = newEdgeS0 - actS0Data[i].lastPulse; //calculate the interval between last valid pulse edge and this edge 40 | actS0Data[i].watt = (3600000000.0 / pulseInterval) / actS0Settings[i].ppkwh; 41 | if ((unsigned long)(actS0Data[i].nextReport - newEdgeS0) > MINREPORTEDS0TIME) { //pulse seen in standby interval so report directly 42 | actS0Data[i].nextReport = 0; // report now 43 | } 44 | } 45 | actS0Data[i].lastPulse = newEdgeS0; // store this edge to compare in next pulses for valid pulse and calculate watt 46 | actS0Data[i].pulses++; 47 | actS0Data[i].pulsesTotal++; 48 | actS0Data[i].goodPulses++; 49 | actS0Data[i].avgPulseWidth = ((actS0Data[i].avgPulseWidth * (actS0Data[i].goodPulses - 1)) + curPulseWidth ) / actS0Data[i].goodPulses; 50 | badEdge[i] = false; //set it to false again to allow to count two bad edges as a new bad pulse because we know we had a good pulse now 51 | } else { 52 | if (badEdge[i]) actS0Data[i].badPulses++; //there was already an edge before so count this one as a bad pulse 53 | badEdge[i] = !badEdge[i]; //for now count it as a bad edge (if it is a edge for a good pulse, this will reset to false a few lines above). The bool is for not counting each edge as a bad pulse, but only two bad edges. 54 | } 55 | lastEdgeS0[i] = newEdgeS0; //store this edge time for next use 56 | } 57 | 58 | IRAM_ATTR void onS0Pulse1Change() { 59 | countPulse(0); //port 1, index 0 of array 60 | } 61 | 62 | IRAM_ATTR void onS0Pulse2Change() { 63 | countPulse(1); //port 2, index 1 of array 64 | } 65 | 66 | 67 | void initS0Sensors(s0SettingsStruct s0Settings[]) { 68 | //setup s0 port 1 69 | 70 | //TODO: check if this is still necessary 71 | //actS0Settings[0].gpiopin = s0Settings[0].gpiopin; 72 | actS0Settings[0].gpiopin = DEFAULT_S0_PIN_1; 73 | actS0Settings[0].ppkwh = s0Settings[0].ppkwh; 74 | actS0Settings[0].lowerPowerInterval = s0Settings[0].lowerPowerInterval; 75 | actS0Settings[0].minimalPulseWidth = s0Settings[0].minimalPulseWidth; 76 | actS0Settings[0].maximalPulseWidth = s0Settings[0].maximalPulseWidth; 77 | 78 | pinMode(actS0Settings[0].gpiopin, INPUT_PULLUP); 79 | attachInterrupt(digitalPinToInterrupt(actS0Settings[0].gpiopin), onS0Pulse1Change, CHANGE); 80 | actS0Data[0].nextReport = millis() + MINREPORTEDS0TIME; //initial report after interval, not directly at boot 81 | 82 | //setup s0 port 2 83 | 84 | //TODO: check if this is still necessary 85 | //actS0Settings[1].gpiopin = s0Settings[1].gpiopin; 86 | actS0Settings[1].gpiopin = DEFAULT_S0_PIN_2; 87 | actS0Settings[1].ppkwh = s0Settings[1].ppkwh; 88 | actS0Settings[1].lowerPowerInterval = s0Settings[1].lowerPowerInterval; 89 | actS0Settings[1].minimalPulseWidth = s0Settings[1].minimalPulseWidth; 90 | actS0Settings[1].maximalPulseWidth = s0Settings[1].maximalPulseWidth; 91 | 92 | pinMode(actS0Settings[1].gpiopin, INPUT_PULLUP); 93 | attachInterrupt(digitalPinToInterrupt(actS0Settings[1].gpiopin), onS0Pulse2Change, CHANGE); 94 | actS0Data[1].nextReport = millis() + MINREPORTEDS0TIME; //initial report after interval, not directly at boot 95 | } 96 | 97 | void restore_s0_Watthour(int s0Port, float watthour) { 98 | if ((s0Port == 1) || (s0Port == 2)) { 99 | unsigned int newTotal = int(watthour * (actS0Settings[s0Port - 1].ppkwh / 1000.0)); 100 | if (newTotal > actS0Data[s0Port - 1].pulsesTotal) { 101 | noInterrupts(); 102 | actS0Data[s0Port - 1].pulsesTotal = newTotal; 103 | interrupts(); 104 | } 105 | } 106 | } 107 | 108 | 109 | 110 | void s0Loop(PubSubClient &mqtt_client, void (*log_message)(char*), char* mqtt_topic_base, s0SettingsStruct s0Settings[]) { 111 | 112 | unsigned long millisThisLoop = millis(); 113 | 114 | for (int i = 0 ; i < NUM_S0_COUNTERS ; i++) { 115 | char tmp_log_msg[256]; 116 | 117 | //report after nextReport 118 | if (millisThisLoop > actS0Data[i].nextReport) { 119 | 120 | unsigned long lastPulseInterval = millisThisLoop - actS0Data[i].lastPulse; 121 | unsigned long calcMaxWatt = (3600000000.0 / lastPulseInterval) / actS0Settings[i].ppkwh; //calculate the maximum watt was is possible without receiving pulses during the report interval 122 | 123 | if (actS0Data[i].watt < ((3600000.0 / actS0Settings[i].ppkwh) / actS0Settings[i].lowerPowerInterval) ) { //watt is lower than possible in lower power interval time, so we are in low power counting mode 124 | actS0Data[i].nextReport = millisThisLoop + 1000 * actS0Settings[i].lowerPowerInterval; 125 | if ((actS0Data[i].watt) / 2 > calcMaxWatt) { //last known watt is higher than possible for the interval, so we need to bring it down fast 126 | actS0Data[i].watt = calcMaxWatt / 2; 127 | } 128 | } 129 | else { // we are in normal counting mode, report each MINREPORTEDS0TIME 130 | actS0Data[i].nextReport = millisThisLoop + MINREPORTEDS0TIME; 131 | if (actS0Data[i].watt > calcMaxWatt) { //last known watt is higher than possible since last report, so bring it down to wat is possible 132 | actS0Data[i].watt = calcMaxWatt; 133 | } 134 | } 135 | 136 | float Watthour = (actS0Data[i].pulses * ( 1000.0 / actS0Settings[i].ppkwh)); 137 | float WatthourTotal = (actS0Data[i].pulsesTotal * ( 1000.0 / actS0Settings[i].ppkwh)); 138 | 139 | noInterrupts(); 140 | actS0Data[i].pulses = 0; //per message we report new wattHour, so pulses should be zero at start new message 141 | interrupts(); 142 | 143 | //report using mqtt 144 | char log_msg[256]; 145 | char mqtt_topic[256]; 146 | char valueStr[20]; 147 | 148 | //debug 149 | /* 150 | noInterrupts(); 151 | int j = 0; 152 | while (allLastEdgeS0Index[i] > 0) { 153 | allLastEdgeS0Index[i]--; 154 | sprintf_P(log_msg, PSTR("Pulse widths seen on S0 port %d: Width: %lu"), (i + 1), allLastEdgeS0[i][j] ); 155 | //log_message(log_msg); 156 | Serial1.println(log_msg); 157 | j++; 158 | } 159 | interrupts(); 160 | */ 161 | //end debug 162 | 163 | sprintf_P(log_msg, PSTR("Pulses seen on S0 port %d: Good: %lu Bad: %lu Average good pulse width: %i"), (i + 1), actS0Data[i].goodPulses, actS0Data[i].badPulses, actS0Data[i].avgPulseWidth); 164 | log_message(log_msg); 165 | 166 | sprintf_P(log_msg, PSTR("Measured Watthour on S0 port %d: %.2f"), (i + 1), Watthour ); 167 | log_message(log_msg); 168 | sprintf(valueStr, "%.2f", Watthour); 169 | sprintf_P(mqtt_topic, PSTR("%s/%s/Watthour/%d"), mqtt_topic_base, mqtt_topic_s0, (i + 1)); 170 | mqtt_client.publish(mqtt_topic, valueStr, MQTT_RETAIN_VALUES); 171 | 172 | sprintf(log_msg, PSTR("Measured total Watthour on S0 port %d: %.2f"), (i + 1), WatthourTotal ); 173 | log_message(log_msg); 174 | sprintf(valueStr, "%.2f", WatthourTotal); 175 | sprintf(mqtt_topic, PSTR("%s/%s/WatthourTotal/%d"), mqtt_topic_base, mqtt_topic_s0, (i + 1)); 176 | mqtt_client.publish(mqtt_topic, valueStr, MQTT_RETAIN_VALUES); 177 | sprintf(log_msg, PSTR("Calculated Watt on S0 port %d: %u"), (i + 1), actS0Data[i].watt); 178 | log_message(log_msg); 179 | sprintf(valueStr, "%u", actS0Data[i].watt); 180 | sprintf(mqtt_topic, PSTR("%s/%s/Watt/%d"), mqtt_topic_base, mqtt_topic_s0, (i + 1)); 181 | mqtt_client.publish(mqtt_topic, valueStr, MQTT_RETAIN_VALUES); 182 | //update GUI over websocket 183 | sprintf_P(log_msg, PSTR("{\"data\": {\"s0values\": {\"s0port\": %d, \"Watt\": %u, \"Watthour\": %.2f, \"WatthourTotal\": %.2f}}}"), i+1, actS0Data[i].watt,Watthour,WatthourTotal); 184 | websocket_write_all(log_msg, strlen(log_msg)); 185 | } 186 | } 187 | } 188 | 189 | unsigned long jsonPulses[NUM_S0_COUNTERS]; 190 | 191 | void s0JsonOutput(struct webserver_t *client) { 192 | webserver_send_content_P(client, PSTR("["), 1); 193 | for (int i = 0; i < NUM_S0_COUNTERS; i++) { 194 | webserver_send_content_P(client, PSTR("{\"S0 port\":"), 11); 195 | 196 | char str[12]; 197 | itoa(i + 1, str, 10); 198 | webserver_send_content(client, str, strlen(str)); 199 | 200 | webserver_send_content_P(client, PSTR(",\"Watt\":"), 8); 201 | 202 | itoa(actS0Data[i].watt, str, 10); 203 | webserver_send_content(client, str, strlen(str)); 204 | 205 | webserver_send_content_P(client, PSTR(",\"Watthour\":"), 12); 206 | 207 | itoa(((actS0Data[i].pulsesTotal - jsonPulses[i]) * (1000.0 / actS0Settings[i].ppkwh)), str, 10); 208 | webserver_send_content(client, str, strlen(str)); 209 | 210 | jsonPulses[i] = actS0Data[i].pulsesTotal; 211 | 212 | webserver_send_content_P(client, PSTR(",\"WatthourTotal\":"), 17); 213 | 214 | itoa((actS0Data[i].pulsesTotal * (1000.0 / actS0Settings[i].ppkwh)), str, 10); 215 | webserver_send_content(client, str, strlen(str)); 216 | 217 | webserver_send_content_P(client, PSTR(",\"PulseQuality\":"), 16); 218 | 219 | itoa((100 * (actS0Data[i].goodPulses + 1) / (actS0Data[i].goodPulses + actS0Data[i].badPulses + 1)), str, 10); 220 | webserver_send_content(client, str, strlen(str)); 221 | 222 | webserver_send_content_P(client, PSTR(",\"AvgPulseWidth\":"), 17); 223 | 224 | itoa(actS0Data[i].avgPulseWidth, str, 10); 225 | webserver_send_content(client, str, strlen(str)); 226 | 227 | if (i < NUM_S0_COUNTERS - 1) { 228 | webserver_send_content_P(client, PSTR("},"), 2); 229 | } else { 230 | webserver_send_content_P(client, PSTR("}"), 1); 231 | } 232 | } 233 | webserver_send_content_P(client, PSTR("]"), 1); 234 | } 235 | -------------------------------------------------------------------------------- /HeishaMon/s0.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "src/common/webserver.h" 3 | 4 | #define NUM_S0_COUNTERS 2 5 | #if defined(ESP8266) 6 | #define DEFAULT_S0_PIN_1 12 7 | #define DEFAULT_S0_PIN_2 14 8 | #elif defined(ESP32) 9 | #define DEFAULT_S0_PIN_1 1 10 | #define DEFAULT_S0_PIN_2 2 11 | #endif 12 | 13 | struct s0SettingsStruct { 14 | byte gpiopin = 255; 15 | unsigned int ppkwh = 1000; //pulses per Wh of the connected meter 16 | unsigned int lowerPowerInterval = 60; //configurabel low power interval 17 | unsigned int minimalPulseWidth = 25; //configurabel minimal s0 pulse width 18 | unsigned int maximalPulseWidth = 100; //configurabel maximal s0 pulse width 19 | }; 20 | 21 | struct s0DataStruct { 22 | unsigned int pulses = 0; //number of pulses since last report 23 | unsigned int pulsesTotal = 0; //total pulses measured from begin 24 | unsigned int watt = 0; //calculated average power 25 | unsigned long lastPulse = 0; //last pulse in millis 26 | unsigned long nextReport = 0; //next time we reported the s0 value in millis 27 | unsigned long goodPulses = 0; 28 | unsigned long badPulses = 0; 29 | unsigned int avgPulseWidth = 0; 30 | }; 31 | 32 | void initS0Sensors(s0SettingsStruct s0Settings[]); 33 | void restore_s0_Watthour(int s0Port, float watthour); 34 | void s0Loop(PubSubClient &mqtt_client, void (*log_message)(char*), char* mqtt_topic_base, s0SettingsStruct s0Settings[]); 35 | void s0JsonOutput(struct webserver_t *client); 36 | -------------------------------------------------------------------------------- /HeishaMon/src/common/base64.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. 7 | * 8 | * This file contains Original Code and/or Modifications of Original Code 9 | * as defined in and that are subject to the Apple Public Source License 10 | * Version 2.0 (the 'License'). You may not use this file except in 11 | * compliance with the License. Please obtain a copy of the License at 12 | * http://www.opensource.apple.com/apsl/ and read it before using this 13 | * file. 14 | * 15 | * The Original Code and all software distributed under the License are 16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 20 | * Please see the License for the specific language governing rights and 21 | * limitations under the License. 22 | * 23 | * @APPLE_LICENSE_HEADER_END@ 24 | */ 25 | /* ==================================================================== 26 | * Copyright (c) 1995-1999 The Apache Group. All rights reserved. 27 | * 28 | * Redistribution and use in source and binary forms, with or without 29 | * modification, are permitted provided that the following conditions 30 | * are met: 31 | * 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 35 | * 2. Redistributions in binary form must reproduce the above copyright 36 | * notice, this list of conditions and the following disclaimer in 37 | * the documentation and/or other materials provided with the 38 | * distribution. 39 | * 40 | * 3. All advertising materials mentioning features or use of this 41 | * software must display the following acknowledgment: 42 | * "This product includes software developed by the Apache Group 43 | * for use in the Apache HTTP server project (http://www.apache.org/)." 44 | * 45 | * 4. The names "Apache Server" and "Apache Group" must not be used to 46 | * endorse or promote products derived from this software without 47 | * prior written permission. For written permission, please contact 48 | * apache@apache.org. 49 | * 50 | * 5. Products derived from this software may not be called "Apache" 51 | * nor may "Apache" appear in their names without prior written 52 | * permission of the Apache Group. 53 | * 54 | * 6. Redistributions of any form whatsoever must retain the following 55 | * acknowledgment: 56 | * "This product includes software developed by the Apache Group 57 | * for use in the Apache HTTP server project (http://www.apache.org/)." 58 | * 59 | * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY 60 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 62 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR 63 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 64 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 65 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 66 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 68 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 69 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 70 | * OF THE POSSIBILITY OF SUCH DAMAGE. 71 | * ==================================================================== 72 | * 73 | * This software consists of voluntary contributions made by many 74 | * individuals on behalf of the Apache Group and was originally based 75 | * on public domain software written at the National Center for 76 | * Supercomputing Applications, University of Illinois, Urbana-Champaign. 77 | * For more information on the Apache Group and the Apache HTTP server 78 | * project, please see . 79 | * 80 | */ 81 | 82 | /* Base64 encoder/decoder. Originally Apache file ap_base64.c 83 | */ 84 | 85 | #include 86 | 87 | #include "base64.h" 88 | 89 | /* aaaack but it's fast and const should make it shared text page. */ 90 | static const unsigned char pr2six[256] = 91 | { 92 | /* ASCII table */ 93 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 94 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 95 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 96 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 97 | 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 98 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 99 | 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 100 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, 101 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 102 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 103 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 104 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 105 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 106 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 107 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 108 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 109 | }; 110 | 111 | int Base64decode_len(const char *bufcoded) 112 | { 113 | int nbytesdecoded; 114 | register const unsigned char *bufin; 115 | register int nprbytes; 116 | 117 | bufin = (const unsigned char *) bufcoded; 118 | while (pr2six[*(bufin++)] <= 63); 119 | 120 | nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; 121 | nbytesdecoded = ((nprbytes + 3) / 4) * 3; 122 | 123 | return nbytesdecoded + 1; 124 | } 125 | 126 | int Base64decode(char *bufplain, const char *bufcoded) 127 | { 128 | int nbytesdecoded; 129 | register const unsigned char *bufin; 130 | register unsigned char *bufout; 131 | register int nprbytes; 132 | 133 | bufin = (const unsigned char *) bufcoded; 134 | while (pr2six[*(bufin++)] <= 63); 135 | nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; 136 | nbytesdecoded = ((nprbytes + 3) / 4) * 3; 137 | 138 | bufout = (unsigned char *) bufplain; 139 | bufin = (const unsigned char *) bufcoded; 140 | 141 | while (nprbytes > 4) { 142 | *(bufout++) = 143 | (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); 144 | *(bufout++) = 145 | (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); 146 | *(bufout++) = 147 | (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); 148 | bufin += 4; 149 | nprbytes -= 4; 150 | } 151 | 152 | /* Note: (nprbytes == 1) would be an error, so just ingore that case */ 153 | if (nprbytes > 1) { 154 | *(bufout++) = 155 | (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); 156 | } 157 | if (nprbytes > 2) { 158 | *(bufout++) = 159 | (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); 160 | } 161 | if (nprbytes > 3) { 162 | *(bufout++) = 163 | (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); 164 | } 165 | 166 | *(bufout++) = '\0'; 167 | nbytesdecoded -= (4 - nprbytes) & 3; 168 | return nbytesdecoded; 169 | } 170 | 171 | static const char basis_64[] = 172 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 173 | 174 | int Base64encode_len(int len) 175 | { 176 | return ((len + 2) / 3 * 4) + 1; 177 | } 178 | 179 | int Base64encode(char *encoded, const char *string, int len) 180 | { 181 | int i; 182 | char *p; 183 | 184 | p = encoded; 185 | for (i = 0; i < len - 2; i += 3) { 186 | *p++ = basis_64[(string[i] >> 2) & 0x3F]; 187 | *p++ = basis_64[((string[i] & 0x3) << 4) | 188 | ((int) (string[i + 1] & 0xF0) >> 4)]; 189 | *p++ = basis_64[((string[i + 1] & 0xF) << 2) | 190 | ((int) (string[i + 2] & 0xC0) >> 6)]; 191 | *p++ = basis_64[string[i + 2] & 0x3F]; 192 | } 193 | if (i < len) { 194 | *p++ = basis_64[(string[i] >> 2) & 0x3F]; 195 | if (i == (len - 1)) { 196 | *p++ = basis_64[((string[i] & 0x3) << 4)]; 197 | *p++ = '='; 198 | } 199 | else { 200 | *p++ = basis_64[((string[i] & 0x3) << 4) | 201 | ((int) (string[i + 1] & 0xF0) >> 4)]; 202 | *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; 203 | } 204 | *p++ = '='; 205 | } 206 | 207 | *p++ = '\0'; 208 | return p - encoded; 209 | } 210 | -------------------------------------------------------------------------------- /HeishaMon/src/common/base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Adam Rudd. 3 | * See LICENSE for more information 4 | */ 5 | #ifndef _BASE64_H 6 | #define _BASE64_H 7 | 8 | int Base64decode_len(const char *bufcoded); 9 | int Base64decode(char *bufplain, const char *bufcoded); 10 | int Base64encode_len(int len); 11 | int Base64encode(char *encoded, const char *string, int len); 12 | 13 | #endif // _BASE64_H 14 | -------------------------------------------------------------------------------- /HeishaMon/src/common/log.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include "mem.h" 16 | #include "../../webfunctions.h" 17 | 18 | extern settingsStruct heishamonSettings; 19 | extern PubSubClient mqtt_client; 20 | extern const char* mqtt_logtopic; 21 | 22 | void _logprintln(const char *file, unsigned int line, char *msg) { 23 | if(heishamonSettings.logSerial1) { 24 | #if defined(ESP8266) 25 | Serial1.print(millis()); 26 | Serial1.print(": "); 27 | Serial1.println(msg); 28 | #elif defined(ESP32) 29 | Serial.print(millis()); 30 | Serial.print(": "); 31 | Serial.println(msg); 32 | #endif 33 | } 34 | websocket_write_all(msg, strlen(msg)); 35 | } 36 | 37 | void _logprintf(const char *file, unsigned int line, char *fmt, ...) { 38 | char *str = NULL; 39 | 40 | va_list ap, apcpy; 41 | va_copy(apcpy, ap); 42 | va_start(apcpy, fmt); 43 | 44 | int bytes = vsnprintf(NULL, 0, fmt, apcpy); 45 | 46 | va_end(apcpy); 47 | if((str = (char *)MALLOC(bytes+1)) == NULL) { 48 | OUT_OF_MEMORY 49 | } 50 | va_start(ap, fmt); 51 | vsprintf(str, fmt, ap); 52 | va_end(ap); 53 | 54 | _logprintln(file, line, str); 55 | 56 | FREE(str); 57 | } 58 | 59 | void _logprintln_P(const char *file, unsigned int line, const __FlashStringHelper *msg) { 60 | PGM_P p = (PGM_P)msg; 61 | int len = strlen_P((const char *)p); 62 | char *str = (char *)MALLOC(len+1); 63 | if(str == NULL) { 64 | OUT_OF_MEMORY 65 | } 66 | strcpy_P(str, p); 67 | 68 | _logprintln(file, line, str); 69 | 70 | FREE(str); 71 | } 72 | 73 | void _logprintf_P(const char *file, unsigned int line, const __FlashStringHelper *fmt, ...) { 74 | PGM_P p = (PGM_P)fmt; 75 | int len = strlen_P((const char *)p); 76 | char *foo = (char *)MALLOC(len+1); 77 | if(foo == NULL) { 78 | OUT_OF_MEMORY 79 | } 80 | strcpy_P(foo, p); 81 | 82 | char *str = NULL; 83 | 84 | va_list ap, apcpy; 85 | va_copy(apcpy, ap); 86 | va_start(apcpy, fmt); 87 | 88 | int bytes = vsnprintf(NULL, 0, foo, apcpy); 89 | 90 | va_end(apcpy); 91 | if((str = (char *)MALLOC(bytes+1)) == NULL) { 92 | OUT_OF_MEMORY 93 | } 94 | va_start(ap, fmt); 95 | vsprintf(str, foo, ap); 96 | va_end(ap); 97 | 98 | _logprintln(file, line, str); 99 | 100 | FREE(foo); 101 | FREE(str); 102 | } -------------------------------------------------------------------------------- /HeishaMon/src/common/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _LOG_H_ 10 | #define _LOG_H_ 11 | 12 | #include 13 | 14 | #define logprintln(a) _logprintln(__FILE__, __LINE__, a) 15 | #define logprintf(a, ...) _logprintf(__FILE__, __LINE__, a, ##__VA_ARGS__) 16 | #define logprintln_P(a) _logprintln_P(__FILE__, __LINE__, a) 17 | #define logprintf_P(a, ...) _logprintf_P(__FILE__, __LINE__, a, ##__VA_ARGS__) 18 | 19 | void _logprintln(const char *file, unsigned int line, char *msg); 20 | void _logprintf(const char *file, unsigned int line, char *fmt, ...); 21 | void _logprintln_P(const char *file, unsigned int line, const __FlashStringHelper *msg); 22 | void _logprintf_P(const char *file, unsigned int line, const __FlashStringHelper *fmt, ...); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /HeishaMon/src/common/mem.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | unsigned int alignedbuffer(int v) { 10 | #if defined(ESP8266) 11 | return (v + 3) & ~0x3; 12 | #else 13 | return v; 14 | #endif 15 | } 16 | -------------------------------------------------------------------------------- /HeishaMon/src/common/mem.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _MEM_H_ 10 | #define _MEM_H_ 11 | 12 | unsigned int alignedbytes(int v); 13 | unsigned int alignedbuffer(int v); 14 | 15 | #define OUT_OF_MEMORY while(0) { } 16 | 17 | #define STRDUP strdup 18 | #define REALLOC realloc 19 | #define CALLOC calloc 20 | #define MALLOC malloc 21 | #define FREE(a) do { free(a); (a) = NULL; } while(0) 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /HeishaMon/src/common/progmem.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef __PROGMEM_H_ 10 | #define __PROGMEM_H_ 11 | 12 | #include 13 | 14 | #define _F(a) (char *)(String(F(a)).c_str()) 15 | 16 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/common/sha1.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Teeny SHA-1 3 | * 4 | * The below sha1digest() calculates a SHA-1 hash value for a 5 | * specified data buffer and generates a hex representation of the 6 | * result. This implementation is a re-forming of the SHA-1 code at 7 | * https://github.com/jinqiangshou/EncryptionLibrary. 8 | * 9 | * Copyright (c) 2017 CTrabant 10 | * 11 | * License: MIT, see included LICENSE file for details. 12 | * 13 | * To use the sha1digest() function either copy it into an existing 14 | * project source code file or include this file in a project and put 15 | * the declaration (example below) in the sources files where needed. 16 | ******************************************************************************/ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | /* Declaration: 24 | extern int sha1digest(uint8_t *digest, char *hexdigest, const uint8_t *data, size_t databytes); 25 | */ 26 | 27 | /******************************************************************************* 28 | * sha1digest: https://github.com/CTrabant/teeny-sha1 29 | * 30 | * Calculate the SHA-1 value for supplied data buffer and generate a 31 | * text representation in hexadecimal. 32 | * 33 | * Based on https://github.com/jinqiangshou/EncryptionLibrary, credit 34 | * goes to @jinqiangshou, all new bugs are mine. 35 | * 36 | * @input: 37 | * data -- data to be hashed 38 | * databytes -- bytes in data buffer to be hashed 39 | * 40 | * @output: 41 | * digest -- the result, MUST be at least 20 bytes 42 | * hexdigest -- the result in hex, MUST be at least 41 bytes 43 | * 44 | * At least one of the output buffers must be supplied. The other, if not 45 | * desired, may be set to NULL. 46 | * 47 | * @return: 0 on success and non-zero on error. 48 | ******************************************************************************/ 49 | int 50 | sha1digest(uint8_t *digest, char *hexdigest, const uint8_t *data, size_t databytes) 51 | { 52 | #define SHA1ROTATELEFT(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 53 | 54 | uint32_t W[80]; 55 | uint32_t H[] = {0x67452301, 56 | 0xEFCDAB89, 57 | 0x98BADCFE, 58 | 0x10325476, 59 | 0xC3D2E1F0}; 60 | uint32_t a; 61 | uint32_t b; 62 | uint32_t c; 63 | uint32_t d; 64 | uint32_t e; 65 | uint32_t f = 0; 66 | uint32_t k = 0; 67 | 68 | uint32_t idx; 69 | uint32_t lidx; 70 | uint32_t widx; 71 | uint32_t didx = 0; 72 | 73 | int32_t wcount; 74 | uint32_t temp; 75 | uint64_t databits = ((uint64_t)databytes) * 8; 76 | uint32_t loopcount = (databytes + 8) / 64 + 1; 77 | uint32_t tailbytes = 64 * loopcount - databytes; 78 | uint8_t datatail[128] = {0}; 79 | 80 | if (!digest && !hexdigest) 81 | return -1; 82 | 83 | if (!data) 84 | return -1; 85 | 86 | /* Pre-processing of data tail (includes padding to fill out 512-bit chunk): 87 | Add bit '1' to end of message (big-endian) 88 | Add 64-bit message length in bits at very end (big-endian) */ 89 | datatail[0] = 0x80; 90 | datatail[tailbytes - 8] = (uint8_t) (databits >> 56 & 0xFF); 91 | datatail[tailbytes - 7] = (uint8_t) (databits >> 48 & 0xFF); 92 | datatail[tailbytes - 6] = (uint8_t) (databits >> 40 & 0xFF); 93 | datatail[tailbytes - 5] = (uint8_t) (databits >> 32 & 0xFF); 94 | datatail[tailbytes - 4] = (uint8_t) (databits >> 24 & 0xFF); 95 | datatail[tailbytes - 3] = (uint8_t) (databits >> 16 & 0xFF); 96 | datatail[tailbytes - 2] = (uint8_t) (databits >> 8 & 0xFF); 97 | datatail[tailbytes - 1] = (uint8_t) (databits >> 0 & 0xFF); 98 | 99 | /* Process each 512-bit chunk */ 100 | for (lidx = 0; lidx < loopcount; lidx++) 101 | { 102 | /* Compute all elements in W */ 103 | memset (W, 0, 80 * sizeof (uint32_t)); 104 | 105 | /* Break 512-bit chunk into sixteen 32-bit, big endian words */ 106 | for (widx = 0; widx <= 15; widx++) 107 | { 108 | wcount = 24; 109 | 110 | /* Copy byte-per byte from specified buffer */ 111 | while (didx < databytes && wcount >= 0) 112 | { 113 | W[widx] += (((uint32_t)data[didx]) << wcount); 114 | didx++; 115 | wcount -= 8; 116 | } 117 | /* Fill out W with padding as needed */ 118 | while (wcount >= 0) 119 | { 120 | W[widx] += (((uint32_t)datatail[didx - databytes]) << wcount); 121 | didx++; 122 | wcount -= 8; 123 | } 124 | } 125 | 126 | /* Extend the sixteen 32-bit words into eighty 32-bit words, with potential optimization from: 127 | "Improving the Performance of the Secure Hash Algorithm (SHA-1)" by Max Locktyukhin */ 128 | for (widx = 16; widx <= 31; widx++) 129 | { 130 | W[widx] = SHA1ROTATELEFT ((W[widx - 3] ^ W[widx - 8] ^ W[widx - 14] ^ W[widx - 16]), 1); 131 | } 132 | for (widx = 32; widx <= 79; widx++) 133 | { 134 | W[widx] = SHA1ROTATELEFT ((W[widx - 6] ^ W[widx - 16] ^ W[widx - 28] ^ W[widx - 32]), 2); 135 | } 136 | 137 | /* Main loop */ 138 | a = H[0]; 139 | b = H[1]; 140 | c = H[2]; 141 | d = H[3]; 142 | e = H[4]; 143 | 144 | for (idx = 0; idx <= 79; idx++) 145 | { 146 | if (idx <= 19) 147 | { 148 | f = (b & c) | ((~b) & d); 149 | k = 0x5A827999; 150 | } 151 | else if (idx >= 20 && idx <= 39) 152 | { 153 | f = b ^ c ^ d; 154 | k = 0x6ED9EBA1; 155 | } 156 | else if (idx >= 40 && idx <= 59) 157 | { 158 | f = (b & c) | (b & d) | (c & d); 159 | k = 0x8F1BBCDC; 160 | } 161 | else if (idx >= 60 && idx <= 79) 162 | { 163 | f = b ^ c ^ d; 164 | k = 0xCA62C1D6; 165 | } 166 | temp = SHA1ROTATELEFT (a, 5) + f + e + k + W[idx]; 167 | e = d; 168 | d = c; 169 | c = SHA1ROTATELEFT (b, 30); 170 | b = a; 171 | a = temp; 172 | } 173 | 174 | H[0] += a; 175 | H[1] += b; 176 | H[2] += c; 177 | H[3] += d; 178 | H[4] += e; 179 | } 180 | 181 | /* Store binary digest in supplied buffer */ 182 | if (digest) 183 | { 184 | for (idx = 0; idx < 5; idx++) 185 | { 186 | digest[idx * 4 + 0] = (uint8_t) (H[idx] >> 24); 187 | digest[idx * 4 + 1] = (uint8_t) (H[idx] >> 16); 188 | digest[idx * 4 + 2] = (uint8_t) (H[idx] >> 8); 189 | digest[idx * 4 + 3] = (uint8_t) (H[idx]); 190 | } 191 | } 192 | 193 | /* Store hex version of digest in supplied buffer */ 194 | if (hexdigest) 195 | { 196 | snprintf (hexdigest, 41, "%08x%08x%08x%08x%08x", 197 | H[0],H[1],H[2],H[3],H[4]); 198 | } 199 | 200 | return 0; 201 | } /* End of sha1digest() */ 202 | -------------------------------------------------------------------------------- /HeishaMon/src/common/sha1.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Teeny SHA-1 3 | * 4 | * The below sha1digest() calculates a SHA-1 hash value for a 5 | * specified data buffer and generates a hex representation of the 6 | * result. This implementation is a re-forming of the SHA-1 code at 7 | * https://github.com/jinqiangshou/EncryptionLibrary. 8 | * 9 | * Copyright (c) 2017 CTrabant 10 | * 11 | * License: MIT, see included LICENSE file for details. 12 | * 13 | * To use the sha1digest() function either copy it into an existing 14 | * project source code file or include this file in a project and put 15 | * the declaration (example below) in the sources files where needed. 16 | ******************************************************************************/ 17 | 18 | int sha1digest(uint8_t *digest, char *hexdigest, const uint8_t *data, size_t databytes); -------------------------------------------------------------------------------- /HeishaMon/src/common/stricmp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | int stricmp(char const *a, char const *b) { 13 | if(a == NULL || b == NULL) { 14 | return -1; 15 | } 16 | 17 | for(;a; a++, b++) { 18 | int d = tolower(*a) - tolower(*b); 19 | if(d != 0 || !*a) { 20 | return d; 21 | } 22 | } 23 | return -1; 24 | } 25 | -------------------------------------------------------------------------------- /HeishaMon/src/common/stricmp.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef STRICMP 10 | #define STRICMP 11 | 12 | int stricmp(char const *a, char const *b); 13 | 14 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/common/strncasestr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | unsigned char *strncasestr(unsigned char *str1, const char *str2, uint16_t size) { 14 | uint16_t a = 0, b = 0, c = 0; 15 | uint16_t len = strlen(str2); 16 | for(a=0;a= 65 && ch <= 90) { 19 | ch += 32; 20 | } 21 | if(ch == str2[0] && a+len <= size) { 22 | c = a; 23 | a++; 24 | for(b=1;b<=len;a++, b++) { 25 | ch = str1[a]; 26 | if(ch >= 65 && ch <= 90) { 27 | ch += 32; 28 | } 29 | if(str2[b] != ch) { 30 | break; 31 | } 32 | } 33 | if(b == len) { 34 | return &str1[a-len]; 35 | } 36 | a = c; 37 | } 38 | } 39 | return NULL; 40 | } 41 | -------------------------------------------------------------------------------- /HeishaMon/src/common/strncasestr.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef STRNCASESTR 10 | #define STRNCASESTR 11 | 12 | #include 13 | #include 14 | 15 | /* 16 | * Find the first occurrence of find in s, where the search is limited to the 17 | * first slen characters of s. 18 | */ 19 | unsigned char *strncasestr(unsigned char *str1, const char *str2, uint16_t len); 20 | 21 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/common/strnicmp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "../rules/rules.h" 14 | 15 | #ifdef ESP8266 16 | #include 17 | #endif 18 | 19 | int strnicmp(char const *a, char const *b, size_t len) { 20 | unsigned int i = 0; 21 | 22 | if(a == NULL || b == NULL) { 23 | return -1; 24 | } 25 | if(len == 0) { 26 | return 0; 27 | } 28 | 29 | for(;i++= (void *)MMU_SEC_HEAP) { 33 | x = mmu_get_uint8((void *)&(*a)); 34 | } else { 35 | #endif 36 | x = *a; 37 | #if (!defined(NON32XFER_HANDLER) && defined(MMU_SEC_HEAP)) || defined(COVERALLS) 38 | } 39 | if((void *)b >= (void *)MMU_SEC_HEAP) { 40 | y = mmu_get_uint8((void *)&(*b)); 41 | } else { 42 | #endif 43 | y = *b; 44 | #if (!defined(NON32XFER_HANDLER) && defined(MMU_SEC_HEAP)) || defined(COVERALLS) 45 | } 46 | #endif 47 | int d = tolower(x) - tolower(y); 48 | if(d != 0 || !x || i == len) { 49 | return d; 50 | } 51 | } 52 | return -1; 53 | } -------------------------------------------------------------------------------- /HeishaMon/src/common/strnicmp.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef STRNICMP 10 | #define STRNICMP 11 | 12 | int strnicmp(char const *a, char const *b, size_t len); 13 | 14 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/common/strnstr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | unsigned char *strnstr(unsigned char *str1, const char *str2, uint16_t size) { 14 | uint16_t a = 0, b = 0, c = 0; 15 | uint16_t len = strlen(str2); 16 | for(a=0;a 13 | #include 14 | 15 | /* 16 | * Find the first occurrence of find in s, where the search is limited to the 17 | * first slen characters of s. 18 | */ 19 | unsigned char *strnstr(unsigned char *str1, const char *str2, uint16_t len); 20 | 21 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/common/timerqueue.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #if defined(ESP8266) || defined(ESP32) 10 | #include 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "mem.h" 21 | #include "timerqueue.h" 22 | 23 | static unsigned int lasttime = 0; 24 | static unsigned int *calls = NULL; 25 | static unsigned int nrcalls = 0; 26 | 27 | #if !defined(ESP8266) && !defined(ESP32) 28 | static unsigned int micros() { 29 | struct timeval tv; 30 | gettimeofday(&tv,NULL); 31 | 32 | return 1000000 * tv.tv_sec + tv.tv_usec;; 33 | } 34 | #endif 35 | 36 | static void timerqueue_sort() { 37 | int matched = 1; 38 | while(matched) { 39 | int a = 0; 40 | matched = 0; 41 | for(a=0;aremove < timerqueue[a+1]->remove || 43 | (timerqueue[a]->remove == timerqueue[a+1]->remove && timerqueue[a]->sec > timerqueue[a+1]->sec) || 44 | (timerqueue[a]->remove == timerqueue[a+1]->remove && timerqueue[a]->sec == timerqueue[a+1]->sec && timerqueue[a]->usec > timerqueue[a+1]->usec)) { 45 | struct timerqueue_t *node = timerqueue[a+1]; 46 | timerqueue[a+1] = timerqueue[a]; 47 | timerqueue[a] = node; 48 | matched = 1; 49 | break; 50 | } 51 | } 52 | } 53 | } 54 | 55 | struct timerqueue_t *timerqueue_pop() { 56 | if(timerqueue_size == 0) { 57 | return NULL; 58 | } 59 | struct timerqueue_t *x = timerqueue[0]; 60 | timerqueue[0] = timerqueue[timerqueue_size-1]; 61 | 62 | timerqueue_size--; 63 | 64 | if(timerqueue_size == 0) { 65 | free(timerqueue); 66 | timerqueue = NULL; 67 | } else { 68 | if((timerqueue = (struct timerqueue_t **)realloc(timerqueue, sizeof(struct timerqueue_t *)*timerqueue_size)) == NULL) { 69 | #if defined(ESP8266) || defined(ESP32) 70 | //loggingSerial.printf("Out of memory %s:#%d\n", __FUNCTION__, __LINE__); 71 | ESP.restart(); 72 | exit(-1); 73 | #else 74 | fprintf(stderr, "Out of memory %s:#%d\n", __FUNCTION__, __LINE__); 75 | exit(-1); 76 | #endif 77 | } 78 | } 79 | 80 | int a = 0; 81 | for(a=0;asec -= x->sec; 83 | timerqueue[a]->usec -= x->usec; 84 | if(timerqueue[a]->usec < 0) { 85 | timerqueue[a]->sec -= 1; 86 | timerqueue[a]->usec += 1000000; 87 | } 88 | } 89 | 90 | timerqueue_sort(); 91 | 92 | return x; 93 | } 94 | 95 | struct timerqueue_t *timerqueue_peek() { 96 | if(timerqueue_size == 0) { 97 | return NULL; 98 | } 99 | return timerqueue[0]; 100 | } 101 | 102 | void timerqueue_insert(int sec, int usec, int nr) { 103 | struct timerqueue_t *node = NULL; 104 | int a = 0, matched = 0, x = 0, y = 0; 105 | 106 | for(a=0;anr == nr) { 108 | timerqueue[a]->sec = sec; 109 | timerqueue[a]->usec = usec; 110 | if(sec <= 0 && usec <= 0) { 111 | timerqueue[a]->remove = 1; 112 | for(x=0;xnr) { 114 | if(nrcalls > 0) { 115 | for(y=x;yremove == 1) { 133 | struct timerqueue_t *node = timerqueue_pop(); 134 | free(node); 135 | } else { 136 | break; 137 | } 138 | } 139 | 140 | return; 141 | } else if(sec == 0 && usec == 0) { 142 | return; 143 | } 144 | 145 | if((timerqueue = (struct timerqueue_t **)realloc(timerqueue, sizeof(struct timerqueue_t *)*(timerqueue_size+1))) == NULL) { 146 | #if defined(ESP8266) || defined(ESP32) 147 | //loggingSerial.printf("Out of memory %s:#%d\n", __FUNCTION__, __LINE__); 148 | ESP.restart(); 149 | exit(-1); 150 | #else 151 | fprintf(stderr, "Out of memory %s:#%d\n", __FUNCTION__, __LINE__); 152 | exit(-1); 153 | #endif 154 | } 155 | 156 | node = (struct timerqueue_t *)malloc(sizeof(struct timerqueue_t)); 157 | if(node == NULL) { 158 | #if defined(ESP8266) || defined(ESP32) 159 | //loggingSerial.printf("Out of memory %s:#%d\n", __FUNCTION__, __LINE__); 160 | ESP.restart(); 161 | exit(-1); 162 | #else 163 | fprintf(stderr, "Out of memory %s:#%d\n", __FUNCTION__, __LINE__); 164 | exit(-1); 165 | #endif 166 | } 167 | memset(node, 0, sizeof(struct timerqueue_t)); 168 | node->sec = sec; 169 | node->usec = usec; 170 | node->nr = nr; 171 | 172 | timerqueue[timerqueue_size++] = node; 173 | timerqueue_sort(); 174 | } 175 | 176 | void timerqueue_update(void) { 177 | struct timeval tv; 178 | unsigned int curtime = 0; 179 | 180 | curtime = micros(); 181 | 182 | unsigned int diff = curtime - lasttime; 183 | unsigned int sec = diff / 1000000; 184 | unsigned int usec = diff - ((diff / 1000000) * 1000000); 185 | int a = 0, x = 0; 186 | 187 | lasttime = curtime; 188 | 189 | for(a=0;asec -= sec; 191 | timerqueue[a]->usec -= usec; 192 | if(timerqueue[a]->usec < 0) { 193 | timerqueue[a]->usec = 1000000 + timerqueue[a]->usec; 194 | timerqueue[a]->sec -= 1; 195 | } 196 | 197 | if(timerqueue[a]->sec < 0 || (timerqueue[a]->sec == 0 && timerqueue[a]->usec <= 0)) { 198 | int nr = timerqueue[a]->nr; 199 | if((calls = (unsigned int *)realloc(calls, (nrcalls+1)*sizeof(unsigned int))) == NULL) { 200 | #if defined(ESP8266) || defined(ESP32) 201 | ///loggingSerial.printf("Out of memory %s:#%d\n", __FUNCTION__, __LINE__); 202 | ESP.restart(); 203 | exit(-1); 204 | #else 205 | fprintf(stderr, "Out of memory %s:#%d\n", __FUNCTION__, __LINE__); 206 | exit(-1); 207 | #endif 208 | } 209 | calls[nrcalls++] = nr; 210 | } 211 | } 212 | for(a=0;asec < 0 || (timerqueue[a]->sec == 0 && timerqueue[a]->usec == 0)) { 214 | struct timerqueue_t *node = timerqueue_pop(); 215 | free(node); 216 | a--; 217 | } 218 | } 219 | while(nrcalls > 0) { 220 | timer_cb(calls[0]); 221 | if(nrcalls > 0) { 222 | for(a=0;a 13 | 14 | typedef struct timerqueue_t { 15 | int sec; 16 | int usec; 17 | int nr; 18 | int remove; 19 | } timerqueue_t; 20 | 21 | extern struct timerqueue_t **timerqueue; 22 | extern int timerqueue_size; 23 | extern void timer_cb(int nr); 24 | 25 | struct timerqueue_t *timerqueue_pop(); 26 | struct timerqueue_t *timerqueue_peek(); 27 | void timerqueue_update(void); 28 | void timerqueue_insert(int sec, int usec, int nr); 29 | 30 | 31 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/common/uint32float.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | 11 | void uint322float(uint32_t in, float *out) { 12 | union { 13 | uint32_t from; 14 | float to; 15 | } pun = { .from = in }; 16 | *out = pun.to; 17 | } 18 | 19 | void float2uint32(float in, uint32_t *out) { 20 | union { 21 | float from; 22 | uint32_t to; 23 | } pun = { .from = in }; 24 | *out = pun.to; 25 | } -------------------------------------------------------------------------------- /HeishaMon/src/common/uint32float.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef __UINT322FLOAT_H_ 10 | #define __UINT322FLOAT_H_ 11 | 12 | #include 13 | 14 | void uint322float(uint32_t in, float *out); 15 | void float2uint32(float in, uint32_t *out); 16 | 17 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/common/webserver.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _WEBSERVER_H_ 10 | #define _WEBSERVER_H_ 11 | 12 | #ifndef MTU_SIZE 13 | #define MTU_SIZE 1460 14 | #endif 15 | 16 | #ifndef WEBSERVER_READ_SIZE 17 | #define WEBSERVER_READ_SIZE 2*MTU_SIZE 18 | #endif 19 | 20 | #ifndef WEBSERVER_BUFFER_SIZE 21 | #ifdef ESP8266 22 | #define WEBSERVER_BUFFER_SIZE 128 23 | #else 24 | #define WEBSERVER_BUFFER_SIZE 512 25 | #endif 26 | #endif 27 | 28 | #ifndef WEBSERVER_MAX_CLIENTS 29 | #define WEBSERVER_MAX_CLIENTS 5 30 | #endif 31 | 32 | #ifndef WEBSERVER_MAX_SENDLIST 33 | #define WEBSERVER_MAX_SENDLIST 0 34 | #endif 35 | 36 | #ifndef WEBSERVER_CLIENT_TIMEOUT 37 | #define WEBSERVER_CLIENT_TIMEOUT 30000 38 | #endif 39 | 40 | #ifndef WEBSERVER_CLIENT_PING_INTERVAL 41 | #define WEBSERVER_CLIENT_PING_INTERVAL 3000 42 | #endif 43 | 44 | #ifndef __linux__ 45 | #include 46 | #include "lwip/opt.h" 47 | #include "lwip/tcp.h" 48 | #include "lwip/inet.h" 49 | #include "lwip/dns.h" 50 | #include "lwip/init.h" 51 | #include "lwip/errno.h" 52 | #include 53 | #include 54 | #include 55 | #endif 56 | 57 | #if !defined(err_t) && !defined(ESP8266) && !defined(ESP32) 58 | #define err_t uint8_t 59 | #endif 60 | 61 | #if !defined(ESP8266) && !defined(ESP32) 62 | typedef struct tcp_pcb { 63 | } tcp_pcb; 64 | 65 | typedef struct pbuf { 66 | unsigned int len; 67 | void *payload; 68 | struct pbuf *next; 69 | } pbuf; 70 | #endif 71 | 72 | typedef struct header_t { 73 | unsigned char *buffer; 74 | uint16_t ptr; 75 | } header_t; 76 | 77 | struct webserver_t; 78 | extern struct webserver_client_t clients[WEBSERVER_MAX_CLIENTS]; 79 | 80 | typedef int8_t (webserver_cb_t)(struct webserver_t *client, void *data); 81 | 82 | typedef struct arguments_t { 83 | unsigned char *name; 84 | unsigned char *value; 85 | uint16_t len; 86 | } arguments_t; 87 | 88 | typedef struct sendlist_t { 89 | union { 90 | void *ptr; 91 | } data; 92 | uint16_t type:1; 93 | uint16_t size:15; 94 | #if WEBSERVER_MAX_SENDLIST == 0 95 | struct sendlist_t *next; 96 | #endif 97 | } sendlist_t; 98 | 99 | #if !defined(ESP8266) && !defined(ESP32) 100 | struct WiFiClient { 101 | int (*write)(unsigned char *, int i); 102 | int (*write_P)(const char *, int i); 103 | int (*available)(); 104 | int (*connected)(); 105 | void (*stop)(); 106 | int (*read)(uint8_t *buffer, int size); 107 | }; 108 | #define PGM_P unsigned char * 109 | #endif 110 | 111 | typedef struct webserver_t { 112 | tcp_pcb *pcb; 113 | WiFiClient *client; 114 | unsigned long lastseen; 115 | unsigned long lastping; 116 | uint8_t is_websocket:1; 117 | uint8_t reqtype:1; 118 | uint8_t async:1; 119 | uint8_t method:1; 120 | uint8_t chunked:4; 121 | uint8_t step:4; 122 | uint8_t substep:4; 123 | uint16_t ptr; 124 | uint32_t totallen; 125 | uint32_t readlen; 126 | uint16_t content; 127 | uint8_t route; 128 | #if WEBSERVER_MAX_SENDLIST == 0 129 | struct sendlist_t *sendlist; 130 | struct sendlist_t *sendlist_head; 131 | #else 132 | struct sendlist_t sendlist[WEBSERVER_MAX_SENDLIST]; 133 | #endif 134 | webserver_cb_t *callback; 135 | unsigned char buffer[WEBSERVER_BUFFER_SIZE]; 136 | union { 137 | char *boundary; 138 | char *websockkey; 139 | } data; 140 | void *userdata; 141 | } webserver_t; 142 | 143 | typedef struct webserver_client_t { 144 | struct webserver_t data; 145 | } webserver_client_t; 146 | 147 | typedef enum { 148 | WEBSERVER_CLIENT_CONNECTING = 1, 149 | WEBSERVER_CLIENT_REQUEST_METHOD, 150 | WEBSERVER_CLIENT_REQUEST_URI, 151 | WEBSERVER_CLIENT_READ_HEADER, 152 | WEBSERVER_CLIENT_CREATE_HEADER, 153 | WEBSERVER_CLIENT_WRITE, 154 | WEBSERVER_CLIENT_WEBSOCKET, 155 | WEBSERVER_CLIENT_WEBSOCKET_TEXT, 156 | WEBSERVER_CLIENT_SENDING, 157 | WEBSERVER_CLIENT_HEADER, 158 | WEBSERVER_CLIENT_ARGS, 159 | WEBSERVER_CLIENT_CLOSE, 160 | } webserver_steps; 161 | 162 | enum { 163 | WEBSOCKET_OPCODE_CONTINUATION = 0x0, 164 | WEBSOCKET_OPCODE_TEXT = 0x1, 165 | WEBSOCKET_OPCODE_BINARY = 0x2, 166 | WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8, 167 | WEBSOCKET_OPCODE_PING = 0x9, 168 | WEBSOCKET_OPCODE_PONG = 0xa 169 | }; 170 | 171 | int8_t webserver_start(int port, webserver_cb_t *callback, uint8_t async); 172 | void webserver_loop(void); 173 | void websocket_write_all_P(PGM_P data, uint16_t data_len); 174 | void websocket_write_all(char *data, uint16_t data_len); 175 | void websocket_write_P(struct webserver_t *client, PGM_P data, uint16_t data_len); 176 | void websocket_write(struct webserver_t *client, char *data, uint16_t data_len); 177 | void websocket_send_header(struct webserver_t *client, uint8_t opcode, uint16_t data_len); 178 | void webserver_send_content(struct webserver_t *client, char *buf, uint16_t len); 179 | void webserver_send_content_P(struct webserver_t *client, PGM_P buf, uint16_t len); 180 | err_t webserver_async_receive(void *arg, tcp_pcb *pcb, struct pbuf *data, err_t err); 181 | uint8_t webserver_sync_receive(struct webserver_t *client, uint8_t *rbuffer, uint16_t size); 182 | void webserver_loop(void); 183 | int16_t urldecode(const unsigned char *src, int src_len, unsigned char *dst, int dst_len, int is_form_url_encoded); 184 | int8_t webserver_send(struct webserver_t *client, uint16_t code, char *mimetype, uint16_t data_len); 185 | void webserver_client_stop(struct webserver_t *client); 186 | void webserver_reset_client(struct webserver_t *client); 187 | 188 | #endif 189 | -------------------------------------------------------------------------------- /HeishaMon/src/opentherm/opentherm.h: -------------------------------------------------------------------------------- 1 | /* 2 | OpenTherm.h - OpenTherm Library for the ESP8266/Arduino platform 3 | https://github.com/ihormelnyk/OpenTherm 4 | http://ihormelnyk.com/pages/OpenTherm 5 | Licensed under MIT license 6 | Copyright 2018, Ihor Melnyk 7 | 8 | Frame Structure: 9 | P MGS-TYPE SPARE DATA-ID DATA-VALUE 10 | 0 000 0000 00000000 00000000 00000000 11 | */ 12 | 13 | #ifndef OpenTherm_h 14 | #define OpenTherm_h 15 | 16 | #include 17 | #include 18 | 19 | enum OpenThermResponseStatus { 20 | NONE, 21 | SUCCESS, 22 | INVALID, 23 | TIMEOUT 24 | }; 25 | 26 | 27 | enum OpenThermMessageType { 28 | /* Master to Slave */ 29 | READ_DATA = 0b000, 30 | READ = READ_DATA, // for backwared compatibility 31 | WRITE_DATA = 0b001, 32 | WRITE = WRITE_DATA, // for backwared compatibility 33 | INVALID_DATA = 0b010, 34 | RESERVED = 0b011, 35 | /* Slave to Master */ 36 | READ_ACK = 0b100, 37 | WRITE_ACK = 0b101, 38 | DATA_INVALID = 0b110, 39 | UNKNOWN_DATA_ID = 0b111 40 | }; 41 | 42 | typedef OpenThermMessageType OpenThermRequestType; // for backwared compatibility 43 | 44 | enum OpenThermMessageID { 45 | Status, // flag8 / flag8 Master and Slave Status flags. 46 | TSet, // f8.8 Control setpoint ie CH water temperature setpoint (°C) 47 | MConfigMMemberIDcode, // flag8 / u8 Master Configuration Flags / Master MemberID Code 48 | SConfigSMemberIDcode, // flag8 / u8 Slave Configuration Flags / Slave MemberID Code 49 | Command, // u8 / u8 Remote Command 50 | ASFflags, // / OEM-fault-code flag8 / u8 Application-specific fault flags and OEM fault code 51 | RBPflags, // flag8 / flag8 Remote boiler parameter transfer-enable & read/write flags 52 | CoolingControl, // f8.8 Cooling control signal (%) 53 | TsetCH2, // f8.8 Control setpoint for 2e CH circuit (°C) 54 | TrOverride, // f8.8 Remote override room setpoint 55 | TSP, // u8 / u8 Number of Transparent-Slave-Parameters supported by slave 56 | TSPindexTSPvalue, // u8 / u8 Index number / Value of referred-to transparent slave parameter. 57 | FHBsize, // u8 / u8 Size of Fault-History-Buffer supported by slave 58 | FHBindexFHBvalue, // u8 / u8 Index number / Value of referred-to fault-history buffer entry. 59 | MaxRelModLevelSetting, // f8.8 Maximum relative modulation level setting (%) 60 | MaxCapacityMinModLevel, // u8 / u8 Maximum boiler capacity (kW) / Minimum boiler modulation level(%) 61 | TrSet, // f8.8 Room Setpoint (°C) 62 | RelModLevel, // f8.8 Relative Modulation Level (%) 63 | CHPressure, // f8.8 Water pressure in CH circuit (bar) 64 | DHWFlowRate, // f8.8 Water flow rate in DHW circuit. (litres/minute) 65 | DayTime, // special / u8 Day of Week and Time of Day 66 | Date, // u8 / u8 Calendar date 67 | Year, // u16 Calendar year 68 | TrSetCH2, // f8.8 Room Setpoint for 2nd CH circuit (°C) 69 | Tr, // f8.8 Room temperature (°C) 70 | Tboiler, // f8.8 Boiler flow water temperature (°C) 71 | Tdhw, // f8.8 DHW temperature (°C) 72 | Toutside, // f8.8 Outside temperature (°C) 73 | Tret, // f8.8 Return water temperature (°C) 74 | Tstorage, // f8.8 Solar storage temperature (°C) 75 | Tcollector, // f8.8 Solar collector temperature (°C) 76 | TflowCH2, // f8.8 Flow water temperature CH2 circuit (°C) 77 | Tdhw2, // f8.8 Domestic hot water temperature 2 (°C) 78 | Texhaust, // s16 Boiler exhaust temperature (°C) 79 | TdhwSetUBTdhwSetLB = 48, // s8 / s8 DHW setpoint upper & lower bounds for adjustment (°C) 80 | MaxTSetUBMaxTSetLB, // s8 / s8 Max CH water setpoint upper & lower bounds for adjustment (°C) 81 | HcratioUBHcratioLB, // s8 / s8 OTC heat curve ratio upper & lower bounds for adjustment 82 | TdhwSet = 56, // f8.8 DHW setpoint (°C) (Remote parameter 1) 83 | MaxTSet, // f8.8 Max CH water setpoint (°C) (Remote parameters 2) 84 | Hcratio, // f8.8 OTC heat curve ratio (°C) (Remote parameter 3) 85 | RemoteOverrideFunction = 100, // flag8 / - Function of manual and program changes in master and remote room setpoint. 86 | OEMDiagnosticCode = 115, // u16 OEM-specific diagnostic/service code 87 | BurnerStarts, // u16 Number of starts burner 88 | CHPumpStarts, // u16 Number of starts CH pump 89 | DHWPumpValveStarts, // u16 Number of starts DHW pump/valve 90 | DHWBurnerStarts, // u16 Number of starts burner during DHW mode 91 | BurnerOperationHours, // u16 Number of hours that burner is in operation (i.e. flame on) 92 | CHPumpOperationHours, // u16 Number of hours that CH pump has been running 93 | DHWPumpValveOperationHours, // u16 Number of hours that DHW pump has been running or DHW valve has been opened 94 | DHWBurnerOperationHours, // u16 Number of hours that burner is in operation during DHW mode 95 | OpenThermVersionMaster, // f8.8 The implemented version of the OpenTherm Protocol Specification in the master. 96 | OpenThermVersionSlave, // f8.8 The implemented version of the OpenTherm Protocol Specification in the slave. 97 | MasterVersion, // u8 / u8 Master product version number and type 98 | SlaveVersion, // u8 / u8 Slave product version number and type 99 | RemoteParameterSettingsVH = 86, 100 | NominalVentilationValue = 87, 101 | }; 102 | 103 | enum OpenThermStatus { 104 | NOT_INITIALIZED, 105 | READY, 106 | DELAY, 107 | REQUEST_SENDING, 108 | RECEIVE_WAITING, 109 | RECEIVE_START_BIT, 110 | RECEIVE_DATA, 111 | RECEIVE_READY, 112 | RECEIVE_INVALID, 113 | ON_OFF 114 | }; 115 | 116 | enum OpenThermSmartPower { 117 | LOW_POWER, 118 | MEDIUM_POWER, 119 | HIGH_POWER 120 | }; 121 | 122 | class OpenTherm 123 | { 124 | public: 125 | OpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false); 126 | volatile OpenThermStatus status; 127 | void begin(void(*handleInterruptCallback)(void)); 128 | void begin(void(*handleInterruptCallback)(void), void(*processResponseCallback)(unsigned long, OpenThermResponseStatus)); 129 | bool isReady(); 130 | unsigned long sendRequest(unsigned long request); 131 | bool sendResponse(unsigned long request); 132 | bool sendRequestAync(unsigned long request); 133 | unsigned long buildRequest(OpenThermMessageType type, OpenThermMessageID id, unsigned int data); 134 | unsigned long buildResponse(OpenThermMessageType type, OpenThermMessageID id, unsigned int data); 135 | OpenThermResponseStatus getLastResponseStatus(); 136 | //const char *statusToString(OpenThermResponseStatus status); 137 | void handleInterrupt(); 138 | void process(); 139 | void end(); 140 | 141 | bool parity(unsigned long frame); 142 | OpenThermMessageType getMessageType(unsigned long message); 143 | OpenThermMessageID getDataID(unsigned long frame); 144 | //const char *messageTypeToString(OpenThermMessageType message_type); 145 | bool isValidRequest(unsigned long request); 146 | bool isValidResponse(unsigned long response); 147 | 148 | //requests 149 | unsigned long buildSetBoilerStatusRequest(bool enableCentralHeating, bool enableHotWater = false, bool enableCooling = false, bool enableOutsideTemperatureCompensation = false, bool enableCentralHeating2 = false); 150 | unsigned long buildSetBoilerTemperatureRequest(float temperature); 151 | unsigned long buildGetBoilerTemperatureRequest(); 152 | 153 | //responses 154 | bool isFault(unsigned long response); 155 | bool isCentralHeatingActive(unsigned long response); 156 | bool isHotWaterActive(unsigned long response); 157 | bool isFlameOn(unsigned long response); 158 | bool isCoolingActive(unsigned long response); 159 | bool isDiagnostic(unsigned long response); 160 | uint16_t getUInt(const unsigned long response) const; 161 | float getFloat(const unsigned long response) const; 162 | unsigned int temperatureToData(float temperature); 163 | 164 | //basic requests 165 | unsigned long setBoilerStatus(bool enableCentralHeating, bool enableHotWater = false, bool enableCooling = false, bool enableOutsideTemperatureCompensation = false, bool enableCentralHeating2 = false); 166 | bool setBoilerTemperature(float temperature); 167 | float getBoilerTemperature(); 168 | float getReturnTemperature(); 169 | bool setDHWSetpoint(float temperature); 170 | float getDHWTemperature(); 171 | float getModulation(); 172 | float getPressure(); 173 | unsigned char getFault(); 174 | 175 | //smartpower 176 | void setSmartPower(bool state); 177 | bool smartPowerEnabled; 178 | volatile OpenThermSmartPower smartPowerState; 179 | 180 | private: 181 | const int inPin; 182 | const int outPin; 183 | const bool isSlave; 184 | 185 | volatile unsigned long response; 186 | volatile OpenThermResponseStatus responseStatus; 187 | volatile unsigned long responseTimestamp; 188 | volatile byte responseBitIndex; 189 | 190 | bool logicalReceiveHigh = HIGH; 191 | bool logicalSendHigh = HIGH; 192 | 193 | int readState(); 194 | void setActiveState(); 195 | void setIdleState(); 196 | void activateBoiler(); 197 | 198 | void sendBit(bool high); 199 | void(*handleInterruptCallback)(); 200 | void(*processResponseCallback)(unsigned long, OpenThermResponseStatus); 201 | }; 202 | 203 | #ifndef ICACHE_RAM_ATTR 204 | #define ICACHE_RAM_ATTR 205 | #endif 206 | 207 | #endif // OpenTherm_h 208 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/function.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "rules.h" 24 | #include "function.h" 25 | 26 | #include "functions/max.h" 27 | #include "functions/min.h" 28 | #include "functions/coalesce.h" 29 | #include "functions/round.h" 30 | #include "functions/ceil.h" 31 | #include "functions/floor.h" 32 | #include "functions/settimer.h" 33 | #include "functions/isset.h" 34 | #include "functions/concat.h" 35 | #include "functions/print.h" 36 | #include "functions/gpio.h" 37 | 38 | struct rule_function_t rule_functions[] = { 39 | { "max", rule_function_max_callback }, 40 | { "min", rule_function_min_callback }, 41 | { "coalesce", rule_function_coalesce_callback }, 42 | { "round", rule_function_round_callback }, 43 | { "floor", rule_function_floor_callback }, 44 | { "ceil", rule_function_ceil_callback }, 45 | { "setTimer", rule_function_set_timer_callback }, 46 | { "isset", rule_function_isset_callback }, 47 | { "print", rule_function_print_callback }, 48 | { "concat", rule_function_concat_callback }, 49 | { "gpio", rule_function_gpio_callback } 50 | }; 51 | 52 | uint16_t nr_rule_functions = sizeof(rule_functions)/sizeof(rule_functions[0]); 53 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/function.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULE_FUNCTION_H_ 10 | #define _RULE_FUNCTION_H_ 11 | 12 | #include "rules.h" /* rewrite */ 13 | 14 | struct rule_function_t { 15 | const char *name; 16 | int8_t (*callback)(struct rules_t *obj); 17 | } __attribute__((packed)); 18 | 19 | extern struct rule_function_t rule_functions[]; 20 | extern uint16_t nr_rule_functions; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/ceil.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../../common/uint32float.h" 16 | #include "../function.h" 17 | #include "../rules.h" 18 | 19 | int8_t rule_function_ceil_callback(struct rules_t *obj) { 20 | float x = 0, z = 0; 21 | uint8_t nr = rules_gettop(obj); 22 | 23 | if(nr > 1) { 24 | return -1; 25 | } 26 | 27 | switch(rules_type(obj, nr)) { 28 | case VNULL: { 29 | rules_remove(obj, nr--); 30 | rules_pushnil(obj); 31 | return 0; 32 | } break; 33 | case VINTEGER: { 34 | x = (float)rules_tointeger(obj, nr); 35 | } break; 36 | case VFLOAT: { 37 | x = rules_tofloat(obj, nr); 38 | } break; 39 | } 40 | rules_remove(obj, nr--); 41 | 42 | if(modff(x, &z) == 0) { 43 | #ifdef DEBUG 44 | printf("\tround = %d\n", (int)x); 45 | #endif 46 | rules_pushinteger(obj, x); 47 | } else { 48 | #ifdef DEBUG 49 | printf("\tround = %f\n", (int)ceil(x)); 50 | #endif 51 | rules_pushinteger(obj, (int)ceil(x)); 52 | } 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/ceil.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULES_CEIL_H_ 10 | #define _RULES_CEIL_H_ 11 | 12 | #include 13 | #include "../rules.h" 14 | 15 | int8_t rule_function_ceil_callback(struct rules_t *obj); 16 | 17 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/coalesce.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../../common/uint32float.h" 16 | #include "../function.h" 17 | #include "../rules.h" 18 | 19 | int8_t rule_function_coalesce_callback(struct rules_t *obj) { 20 | float x = 0, z = 0; 21 | uint8_t nr = rules_gettop(obj), loop = 1, y = 0; 22 | 23 | for(y=1;y<=nr && loop == 1;y++) { 24 | switch(rules_type(obj, y)) { 25 | case VNULL: { 26 | } break; 27 | case VINTEGER: { 28 | x = (float)rules_tointeger(obj, y); 29 | loop = 0; 30 | } break; 31 | case VFLOAT: { 32 | x = rules_tofloat(obj, y); 33 | loop = 0; 34 | } break; 35 | } 36 | } 37 | while(nr > 0) { 38 | rules_remove(obj, nr--); 39 | } 40 | 41 | if(modff(x, &z) == 0) { 42 | #ifdef DEBUG 43 | printf("\tcoalesce = %d\n", (int)x); 44 | #endif 45 | rules_pushinteger(obj, x); 46 | } else { 47 | #ifdef DEBUG 48 | printf("\tcoalesce = %f\n", x); 49 | #endif 50 | rules_pushfloat(obj, x); 51 | } 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/coalesce.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULES_COALESCE_H_ 10 | #define _RULES_COALESCE_H_ 11 | 12 | #include 13 | #include "../rules.h" 14 | 15 | int8_t rule_function_coalesce_callback(struct rules_t *obj); 16 | 17 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/concat.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifdef ESP8266 10 | #pragma GCC diagnostic warning "-fpermissive" 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "../../common/uint32float.h" 19 | #include "../../common/log.h" 20 | #include "../function.h" 21 | #include "../rules.h" 22 | 23 | int8_t rule_function_concat_callback(struct rules_t *obj) { 24 | uint16_t len = 0, offset = 0; 25 | uint8_t nr = rules_gettop(obj), y = 0; 26 | 27 | for(y=1;y<=nr;y++) { 28 | switch(rules_type(obj, y)) { 29 | case VNULL: { 30 | len += strlen("NULL"); 31 | } break; 32 | case VINTEGER: { 33 | int i = rules_tointeger(obj, y); 34 | len += snprintf(NULL, 0, "%d", i); 35 | } break; 36 | case VFLOAT: { 37 | float f = rules_tofloat(obj, y); 38 | len += snprintf(NULL, 0, "%g", f); 39 | } break; 40 | case VCHAR: { 41 | len += strlen(rules_tostring(obj, y)); 42 | } break; 43 | } 44 | } 45 | 46 | char tmp[len+1] = { '\0' }; 47 | for(y=1;y<=nr;y++) { 48 | switch(rules_type(obj, y)) { 49 | case VNULL: { 50 | offset += snprintf(&tmp[offset], len+1-offset, "NULL"); 51 | } break; 52 | case VINTEGER: { 53 | int i = rules_tointeger(obj, y); 54 | offset += snprintf(&tmp[offset], len+1-offset, "%d", i); 55 | } break; 56 | case VFLOAT: { 57 | float f = rules_tofloat(obj, y); 58 | offset += snprintf(&tmp[offset], len+1-offset, "%g", f); 59 | } break; 60 | case VCHAR: { 61 | offset += snprintf(&tmp[offset], len+1-offset, "%s", rules_tostring(obj, y)); 62 | } break; 63 | } 64 | } 65 | 66 | while(nr > 0) { 67 | rules_remove(obj, nr--); 68 | } 69 | 70 | rules_pushstring(obj, tmp); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/concat.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULES_CONCAT_H_ 10 | #define _RULES_CONCAT_H_ 11 | 12 | #include 13 | #include "../rules.h" 14 | 15 | int8_t rule_function_concat_callback(struct rules_t *obj); 16 | 17 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/floor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../../common/uint32float.h" 16 | #include "../function.h" 17 | #include "../rules.h" 18 | 19 | int8_t rule_function_floor_callback(struct rules_t *obj) { 20 | float x = 0, z = 0; 21 | uint8_t nr = rules_gettop(obj); 22 | 23 | if(nr > 1) { 24 | return -1; 25 | } 26 | 27 | switch(rules_type(obj, nr)) { 28 | case VNULL: { 29 | rules_remove(obj, nr--); 30 | rules_pushnil(obj); 31 | return 0; 32 | } break; 33 | case VINTEGER: { 34 | x = (float)rules_tointeger(obj, nr); 35 | } break; 36 | case VFLOAT: { 37 | x = rules_tofloat(obj, nr); 38 | } break; 39 | } 40 | rules_remove(obj, nr--); 41 | 42 | if(modff(x, &z) == 0) { 43 | #ifdef DEBUG 44 | printf("\tfloor = %d\n", (int)x); 45 | #endif 46 | rules_pushinteger(obj, x); 47 | } else { 48 | #ifdef DEBUG 49 | printf("\tfloor = %d\n", (int)floor(x)); 50 | #endif 51 | rules_pushinteger(obj, (int)floor(x)); 52 | } 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/floor.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULES_FLOOR_H_ 10 | #define _RULES_FLOOR_H_ 11 | 12 | #include 13 | #include "../rules.h" 14 | 15 | int8_t rule_function_floor_callback(struct rules_t *obj); 16 | 17 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/gpio.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../function.h" 16 | #include "../rules.h" 17 | 18 | int8_t rule_function_gpio_callback(struct rules_t *obj) { 19 | int8_t gpio = 0, state = 0; 20 | uint8_t nr = rules_gettop(obj), x = 1; 21 | 22 | if(nr == 1 || nr == 2) { 23 | if(rules_type(obj, x) == VINTEGER) { 24 | gpio = rules_tointeger(obj, x); 25 | rules_remove(obj, x); 26 | #ifdef DEBUG 27 | printf("\tgpio = %d\n", gpio); 28 | #endif 29 | rules_pushinteger(obj, digitalRead(gpio)); 30 | if(nr == 1) { 31 | return 0; 32 | } 33 | } else { 34 | return -1; 35 | } 36 | } 37 | if(nr == 2) { 38 | if(rules_type(obj, x) == VINTEGER) { 39 | state = rules_tointeger(obj, x); 40 | if(state < 0 || state > 1) { 41 | return -1; 42 | } 43 | #ifdef DEBUG 44 | printf("\tstate = %d\n", state); 45 | #endif 46 | rules_remove(obj, x++); 47 | } else { 48 | return -1; 49 | } 50 | digitalWrite(gpio, state); 51 | } else { 52 | return -1; 53 | } 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/gpio.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULES_GPIO_H_ 10 | #define _RULES_GPIO_H_ 11 | 12 | #include 13 | #include "../rules.h" 14 | 15 | int8_t rule_function_gpio_callback(struct rules_t *obj); 16 | 17 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/isset.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../function.h" 16 | #include "../rules.h" 17 | 18 | int8_t rule_function_isset_callback(struct rules_t *obj) { 19 | uint8_t x = rules_gettop(obj); 20 | uint8_t ret = 0; 21 | 22 | if(x < 1 || x > 1) { 23 | return -1; 24 | } 25 | 26 | switch(rules_type(obj, -1)) { 27 | case VNULL: { 28 | ret = 0; 29 | #ifdef DEBUG 30 | printf(".. %s NULL -> 0\n", __FUNCTION__); 31 | #endif 32 | } break; 33 | case VINTEGER: 34 | case VFLOAT: { 35 | ret = 1; 36 | #ifdef DEBUG 37 | printf(".. %s !NULL -> 1\n", __FUNCTION__); 38 | #endif 39 | } break; 40 | } 41 | rules_remove(obj, -1); 42 | rules_pushinteger(obj, ret); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/isset.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULES_ISSET_H_ 10 | #define _RULES_ISSET_H_ 11 | 12 | #include 13 | #include "../rules.h" 14 | 15 | int8_t rule_function_isset_callback(struct rules_t *obj); 16 | 17 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/max.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../../common/uint32float.h" 16 | #include "../function.h" 17 | #include "../rules.h" 18 | 19 | int8_t rule_function_max_callback(struct rules_t *obj) { 20 | float y = 0, x = 0, z = 0, a = 0; 21 | uint8_t nr = rules_gettop(obj); 22 | 23 | while(nr > 0) { 24 | switch(rules_type(obj, nr)) { 25 | case VINTEGER: { 26 | y = (float)rules_tointeger(obj, nr); 27 | } break; 28 | case VFLOAT: { 29 | y = rules_tofloat(obj, nr); 30 | } break; 31 | case VNULL: { 32 | } break; 33 | } 34 | rules_remove(obj, nr--); 35 | if(a == 0) { 36 | a = 1; 37 | x = y; 38 | } else { 39 | x = MAX(x, y); 40 | } 41 | } 42 | 43 | if(modff(x, &z) == 0) { 44 | #ifdef DEBUG 45 | printf("\tmax = %d\n", (int)x); 46 | #endif 47 | rules_pushinteger(obj, x); 48 | } else { 49 | #ifdef DEBUG 50 | printf("\tmax = %f\n", x); 51 | #endif 52 | rules_pushfloat(obj, x); 53 | } 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/max.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULES_MAX_H_ 10 | #define _RULES_MAX_H_ 11 | 12 | #include 13 | #include "../rules.h" 14 | 15 | int8_t rule_function_max_callback(struct rules_t *obj); 16 | 17 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/min.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../../common/uint32float.h" 16 | #include "../function.h" 17 | #include "../rules.h" 18 | 19 | int8_t rule_function_min_callback(struct rules_t *obj) { 20 | float y = 0, x = 0, z = 0, a = 0; 21 | uint8_t nr = rules_gettop(obj); 22 | 23 | while(nr > 0) { 24 | switch(rules_type(obj, nr)) { 25 | case VINTEGER: { 26 | y = (float)rules_tointeger(obj, nr); 27 | } break; 28 | case VFLOAT: { 29 | y = rules_tofloat(obj, nr); 30 | } break; 31 | case VNULL: { 32 | } break; 33 | } 34 | rules_remove(obj, nr--); 35 | if(a == 0) { 36 | a = 1; 37 | x = y; 38 | } else { 39 | x = MIN(x, y); 40 | } 41 | } 42 | 43 | if(modff(x, &z) == 0) { 44 | #ifdef DEBUG 45 | printf("\tmin = %d\n", (int)x); 46 | #endif 47 | rules_pushinteger(obj, x); 48 | } else { 49 | #ifdef DEBUG 50 | printf("\tmin = %f\n", x); 51 | #endif 52 | rules_pushfloat(obj, x); 53 | } 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/min.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULES_MIN_H_ 10 | #define _RULES_MIN_H_ 11 | 12 | #include 13 | #include "../rules.h" 14 | 15 | int8_t rule_function_min_callback(struct rules_t *obj); 16 | 17 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/print.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifdef ESP8266 10 | #pragma GCC diagnostic warning "-fpermissive" 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "../../common/uint32float.h" 19 | #include "../../common/log.h" 20 | #include "../function.h" 21 | #include "../rules.h" 22 | 23 | int8_t rule_function_print_callback(struct rules_t *obj) { 24 | uint16_t len = 0, offset = 0; 25 | uint8_t nr = rules_gettop(obj), y = 0; 26 | 27 | for(y=1;y<=nr;y++) { 28 | switch(rules_type(obj, y)) { 29 | case VNULL: { 30 | len += 4; 31 | } break; 32 | case VINTEGER: { 33 | len += snprintf(NULL, 0, "%d", rules_tointeger(obj, y)); 34 | } break; 35 | case VFLOAT: { 36 | len += snprintf(NULL, 0, "%g", rules_tofloat(obj, y)); 37 | } break; 38 | case VCHAR: { 39 | len += strlen(rules_tostring(obj, y)); 40 | } break; 41 | } 42 | } 43 | 44 | if(len > 0) { 45 | len++; 46 | char out[len] = { '\0' }; 47 | 48 | for(y=1;y<=nr;y++) { 49 | switch(rules_type(obj, y)) { 50 | case VNULL: { 51 | offset += snprintf(&out[offset], len-offset, "NULL"); 52 | } break; 53 | case VINTEGER: { 54 | offset += snprintf(&out[offset], len-offset, "%d", rules_tointeger(obj, y)); 55 | } break; 56 | case VFLOAT: { 57 | offset += snprintf(&out[offset], len-offset, "%g", rules_tofloat(obj, y)); 58 | } break; 59 | case VCHAR: { 60 | offset += snprintf(&out[offset], len-offset, "%s", rules_tostring(obj, y)); 61 | } break; 62 | } 63 | } 64 | logprintf(out); 65 | } 66 | 67 | while(nr > 0) { 68 | rules_remove(obj, nr--); 69 | } 70 | 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/print.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULES_PRINT_H_ 10 | #define _RULES_PRINT_H_ 11 | 12 | #include 13 | #include "../rules.h" 14 | 15 | int8_t rule_function_print_callback(struct rules_t *obj); 16 | 17 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/round.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../../common/uint32float.h" 16 | #include "../function.h" 17 | #include "../rules.h" 18 | 19 | int8_t rule_function_round_callback(struct rules_t *obj) { 20 | float x = 0, z = 0; 21 | uint8_t dec = 0; 22 | uint8_t nr = rules_gettop(obj), y = nr; 23 | 24 | if(nr > 2) { 25 | return -1; 26 | } else if(nr == 2) { 27 | switch(rules_type(obj, nr)) { 28 | case VINTEGER: { 29 | dec = rules_tointeger(obj, nr); 30 | } break; 31 | } 32 | rules_remove(obj, nr--); 33 | } 34 | 35 | switch(rules_type(obj, nr)) { 36 | case VNULL: { 37 | rules_remove(obj, nr--); 38 | rules_pushnil(obj); 39 | return 0; 40 | } break; 41 | case VINTEGER: { 42 | x = (float)rules_tointeger(obj, nr); 43 | } break; 44 | case VFLOAT: { 45 | x = rules_tofloat(obj, nr); 46 | } break; 47 | } 48 | rules_remove(obj, nr--); 49 | 50 | if(modff(x, &z) == 0) { 51 | #ifdef DEBUG 52 | printf("\tround = %d\n", (int)x); 53 | #endif 54 | rules_pushinteger(obj, x); 55 | } else { 56 | if(y == 2) { 57 | uint8_t size = snprintf(NULL, 0, "%.*f", dec, x)+1; 58 | char buf[size] = { '\0' }; 59 | snprintf((char *)&buf, size, "%.*f", dec, x); 60 | #ifdef DEBUG 61 | printf("\tround = %f\n", atof(buf)); 62 | #endif 63 | rules_pushfloat(obj, atof(buf)); 64 | } else { 65 | #ifdef DEBUG 66 | printf("\tround = %d\n", (int)x); 67 | #endif 68 | rules_pushinteger(obj, (int)x); 69 | } 70 | } 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/round.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULES_ROUND_H_ 10 | #define _RULES_ROUND_H_ 11 | 12 | #include 13 | #include "../rules.h" 14 | 15 | int8_t rule_function_round_callback(struct rules_t *obj); 16 | 17 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/settimer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "../function.h" 18 | #include "../../common/mem.h" 19 | #include "../../common/log.h" 20 | #include "../rules.h" 21 | #include "../../common/timerqueue.h" 22 | 23 | int8_t rule_function_set_timer_callback(struct rules_t *obj) { 24 | struct timerqueue_t *node = NULL; 25 | struct itimerval it_val; 26 | uint16_t sec = 0, nr = 0; 27 | uint8_t x = rules_gettop(obj); 28 | 29 | if(x < 2 || x > 2) { 30 | return -1; 31 | } 32 | 33 | switch(rules_type(obj, -1)) { 34 | case VNULL: { 35 | rules_remove(obj, -1); 36 | rules_remove(obj, -1); 37 | return -1; 38 | } break; 39 | case VINTEGER: { 40 | sec = rules_tointeger(obj, -1); 41 | } break; 42 | case VFLOAT: { 43 | sec = (int)rules_tofloat(obj, -1); 44 | } break; 45 | } 46 | rules_remove(obj, -1); 47 | 48 | switch(rules_type(obj, -1)) { 49 | case VNULL: { 50 | rules_remove(obj, -1); 51 | return -1; 52 | } break; 53 | case VINTEGER: { 54 | nr = rules_tointeger(obj, -1); 55 | } break; 56 | case VFLOAT: { 57 | nr = (int)rules_tofloat(obj, -1); 58 | } break; 59 | } 60 | 61 | timerqueue_insert(sec, 0, nr); 62 | 63 | logprintf_P(F("timer #%d set to %d seconds"), nr, sec); 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/functions/settimer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULES_SET_TIMER_H_ 10 | #define _RULES_SET_TIMER_H_ 11 | 12 | #include 13 | #include "../rules.h" 14 | 15 | int8_t rule_function_set_timer_callback(struct rules_t *obj); 16 | void inline timer_cb(void); 17 | 18 | #endif -------------------------------------------------------------------------------- /HeishaMon/src/rules/operator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "../common/mem.h" 24 | #include "rules.h" 25 | #include "operator.h" 26 | 27 | struct rule_operator_t rule_operators[] = { 28 | { OP_EQ, "==", 30, 1 }, 29 | { OP_NE, "!=", 30, 1 }, 30 | { OP_ADD, "+", 60, 1 }, 31 | { OP_SUB, "-", 60, 1 }, 32 | { OP_MUL, "*", 70, 1 }, 33 | { OP_MOD, "%", 70, 1 }, 34 | { OP_AND, "&&", 20, 1 }, 35 | { OP_OR, "||", 10, 1 }, 36 | { OP_DIV, "/", 70, 1 }, 37 | { OP_GE, ">=", 30, 1 }, 38 | { OP_LE, "<=", 30, 1 }, 39 | { OP_LT, "<", 30, 1, }, 40 | { OP_GT, ">", 30, 1 }, 41 | { OP_POW, "^", 80, 2 }, 42 | }; 43 | 44 | uint8_t nr_rule_operators = sizeof(rule_operators)/sizeof(rule_operators[0]); 45 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/operator.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULE_OPERATOR_H_ 10 | #define _RULE_OPERATOR_H_ 11 | 12 | #include "rules.h" /* rewrite */ 13 | 14 | struct rule_operator_t { 15 | uint8_t opcode; 16 | const char *name; 17 | uint8_t precedence; 18 | uint8_t associativity; 19 | } __attribute__((packed)); 20 | 21 | extern struct rule_operator_t rule_operators[]; 22 | extern uint8_t nr_rule_operators; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/rules.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #ifndef _RULES_H_ 11 | #define _RULES_H_ 12 | 13 | #include 14 | #include 15 | #include "stack.h" 16 | 17 | #if !defined(ESP8266) && !defined(ESP32) 18 | #define F 19 | #define MEMPOOL_SIZE 16000 20 | typedef struct pbuf { 21 | struct pbuf *next; 22 | void *payload; 23 | uint16_t tot_len; 24 | uint16_t len; 25 | uint8_t type; 26 | uint8_t flags; 27 | uint16_t ref; 28 | } pbuf; 29 | 30 | typedef struct serial_t { 31 | void (*printf)(const char *fmt, ...); 32 | void (*println)(const char *val); 33 | void (*flush)(void); 34 | } serial_t; 35 | extern struct serial_t Serial; 36 | extern void *MMU_SEC_HEAP; 37 | uint8_t mmu_set_uint8(void *ptr, uint8_t src); 38 | uint8_t mmu_get_uint8(void *ptr); 39 | uint16_t mmu_set_uint16(void *ptr, uint16_t src); 40 | uint16_t mmu_get_uint16(void *ptr); 41 | #elif defined(ESP32) 42 | #include 43 | #include "lwip/pbuf.h" 44 | #define MEMPOOL_SIZE 32*1024 //use 32kb PSRAM on esp32-mini-1-n4r2 (can not assign more than 64kb due to uint16_t in pbuf) 45 | #elif defined(ESP8266) 46 | #include 47 | #include "lwip/pbuf.h" 48 | #ifdef MMU_SEC_HEAP_SIZE 49 | #define MEMPOOL_ADDRESS MMU_SEC_HEAP 50 | #define MEMPOOL_SIZE MMU_SEC_HEAP_SIZE 51 | #else 52 | #define MEMPOOL_SIZE 16000 53 | #endif 54 | #endif 55 | 56 | #define MAX(a,b) \ 57 | ({ __typeof__ (a) _a = (a); \ 58 | __typeof__ (b) _b = (b); \ 59 | _a > _b ? _a : _b; }) 60 | 61 | #define MIN(a,b) \ 62 | ({ __typeof__ (a) _a = (a); \ 63 | __typeof__ (b) _b = (b); \ 64 | _a < _b ? _a : _b; }) 65 | 66 | /* 67 | * Max 32 tokens are allowed 68 | */ 69 | typedef enum { 70 | TOPERATOR = 1, 71 | TFUNCTION = 2, 72 | TSTRING = 3, 73 | TNUMBER = 4, 74 | TNUMBER1 = 5, 75 | TNUMBER2 = 6, 76 | TNUMBER3 = 7, 77 | TEOF = 8, 78 | LPAREN = 9, 79 | RPAREN = 10, 80 | TCOMMA = 11, 81 | TIF = 12, 82 | TELSE = 13, 83 | TELSEIF = 14, 84 | TTHEN = 15, 85 | TEVENT = 16, 86 | TEND = 17, 87 | TVAR = 18, 88 | TASSIGN = 19, 89 | TSEMICOLON = 20, 90 | TTRUE = 21, 91 | TFALSE = 22, 92 | TSTART = 23, 93 | TVALUE = 24, 94 | VCHAR = 25, 95 | VPTR = 26, 96 | VINTEGER = 27, 97 | VFLOAT = 28, 98 | VNULL = 29 99 | } token_types; 100 | 101 | typedef enum { 102 | OP_EQ = 1, 103 | OP_NE = 2, 104 | OP_LT = 3, 105 | OP_LE = 4, 106 | OP_GT = 5, 107 | OP_GE = 6, 108 | OP_AND = 7, 109 | OP_OR = 8, 110 | OP_SUB = 9, 111 | OP_ADD = 10, 112 | OP_DIV = 11, 113 | OP_MUL = 12, 114 | OP_POW = 13, 115 | OP_MOD = 14, 116 | OP_TEST = 15, 117 | OP_JMP = 16, 118 | OP_SETVAL = 17, 119 | OP_GETVAL = 18, 120 | OP_PUSH = 19, 121 | OP_CALL = 20, 122 | OP_CLEAR = 21, 123 | OP_RET = 22 124 | } opcodes; 125 | 126 | typedef struct rules_t { 127 | /* --- PUBLIC MEMBERS --- */ 128 | 129 | /* To what rule do we return after 130 | * being called from another rule. 131 | */ 132 | struct { 133 | struct rules_t *go; 134 | struct rules_t *ret; 135 | } __attribute__((aligned(4))) ctx; 136 | #ifndef NON32XFER_HANDLER 137 | uint32_t nr; 138 | #else 139 | uint8_t nr; 140 | #endif 141 | 142 | const char *name; 143 | 144 | /* --- PRIVATE MEMBERS --- */ 145 | 146 | /* Continue here after we processed 147 | * another rule call. 148 | */ 149 | uint16_t cont; 150 | 151 | void *userdata; 152 | 153 | struct rule_stack_t bc; 154 | struct rule_stack_t *heap; 155 | 156 | } __attribute__((aligned(4))) rules_t; 157 | 158 | typedef struct rule_options_t { 159 | /* 160 | * Identifying callbacks 161 | */ 162 | int8_t (*is_variable_cb)(char *text, uint16_t size); 163 | int8_t (*is_event_cb)(char *text, uint16_t size); 164 | 165 | int8_t (*vm_value_set)(struct rules_t *obj); 166 | int8_t (*vm_value_get)(struct rules_t *obj); 167 | 168 | /* 169 | * Events 170 | */ 171 | int8_t (*event_cb)(struct rules_t *obj, char *name); 172 | void (*done_cb)(struct rules_t *obj); 173 | } rule_options_t; 174 | 175 | extern struct rule_options_t rule_options; 176 | 177 | int8_t rule_token(struct rule_stack_t *obj, uint16_t pos, unsigned char **out); 178 | const char *rule_by_nr(struct rules_t **rule, uint8_t nrrules, uint8_t nr); 179 | int8_t rule_by_name(struct rules_t **rule, uint8_t nrrules, char *name); 180 | int8_t rule_initialize(struct pbuf *input, struct rules_t ***rules, uint8_t *nrrules, struct pbuf *mempool, void *userdata); 181 | int8_t rule_run(struct rules_t *rule, uint8_t validate); 182 | void rules_gc(struct rules_t ***rules, uint8_t *nrrules); 183 | 184 | int8_t rules_pushnil(struct rules_t *obj); 185 | int8_t rules_pushfloat(struct rules_t *obj, float nr); 186 | int8_t rules_pushinteger(struct rules_t *obj, int nr); 187 | int8_t rules_pushstring(struct rules_t *obj, char *str); 188 | 189 | void rules_ref(const char *str); 190 | void rules_unref(const char *str); 191 | 192 | int rules_tointeger(struct rules_t *obj, int8_t pos); 193 | float rules_tofloat(struct rules_t *obj, int8_t pos); 194 | const char *rules_tostring(struct rules_t *obj, int8_t pos); 195 | 196 | void rules_remove(struct rules_t *rule, int8_t pos); 197 | uint8_t rules_gettop(struct rules_t *rule); 198 | uint8_t rules_type(struct rules_t *rule, int8_t pos); 199 | 200 | #if defined(DEBUG) || defined(COVERALLS) 201 | uint16_t rules_memused(void); 202 | #endif 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /HeishaMon/src/rules/stack.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013 - 2016 CurlyMo 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef _RULE_STACK_T_ 10 | #define _RULE_STACK_T_ 11 | 12 | typedef struct rule_stack_t { 13 | uint16_t nrbytes; 14 | uint16_t bufsize; 15 | 16 | unsigned char *buffer; 17 | } __attribute__((aligned(4))) rule_stack_t; 18 | 19 | #endif -------------------------------------------------------------------------------- /HeishaMon/version.h: -------------------------------------------------------------------------------- 1 | static const char* heishamon_version = "3.9"; 2 | 3 | -------------------------------------------------------------------------------- /HeishaMon/webfunctions.h: -------------------------------------------------------------------------------- 1 | #define LWIP_INTERNAL 2 | 3 | #if defined(ESP8266) 4 | #include 5 | #include 6 | #elif defined(ESP32) 7 | #include 8 | #include 9 | #include 10 | #include 11 | #endif 12 | #include 13 | #include 14 | #include 15 | #include "src/common/webserver.h" 16 | #include "dallas.h" 17 | #include "s0.h" 18 | #include "HeishaOT.h" 19 | #include "gpio.h" 20 | 21 | #define HEATPUMP_VALUE_LEN 16 22 | 23 | void log_message(char* string); 24 | 25 | static IPAddress apIP(192, 168, 4, 1); 26 | 27 | struct settingsStruct { 28 | uint16_t waitTime = 5; // how often data is read from heatpump 29 | uint16_t waitDallasTime = 5; // how often temps are read from 1wire 30 | uint16_t dallasResolution = 12; // dallas temp resolution (9 to 12) 31 | uint16_t updateAllTime = 300; // how often all data is resend to mqtt 32 | uint16_t updataAllDallasTime = 300; //how often all 1wire data is resent to mqtt 33 | uint16_t timezone = 0; 34 | 35 | const char* update_path = "/firmware"; 36 | const char* update_username = "admin"; 37 | char wifi_ssid[33] = ""; 38 | char wifi_password[65] = ""; 39 | char wifi_hostname[40] = "HeishaMon"; 40 | char ota_password[40] = "heisha"; 41 | char mqtt_server[65]; 42 | char mqtt_port[6] = "1883"; 43 | char mqtt_username[65]; 44 | char mqtt_password[65]; 45 | char mqtt_topic_base[128] = "panasonic_heat_pump"; 46 | char ntp_servers[254] = "pool.ntp.org"; 47 | 48 | bool force_rules = false; //force rules on boot, even after a crash 49 | bool listenonly = false; //listen only so heishamon can be installed parallel to cz-taw1, set commands will not work though 50 | bool optionalPCB = false; //do we emulate an optional PCB? 51 | bool use_1wire = false; //1wire enabled? 52 | bool use_s0 = false; //s0 enabled? 53 | bool logMqtt = false; //log to mqtt from start 54 | bool logHexdump = false; //log hexdump from start 55 | bool logSerial1 = true; //log to serial1 (gpio2) from start 56 | bool opentherm = false; //opentherm enable flag 57 | bool hotspot = true; //enable wifi hotspot when wifi is not connected 58 | #ifdef ESP32 59 | bool proxy = true; //cztaw proxy port enable flag 60 | #endif 61 | s0SettingsStruct s0Settings[NUM_S0_COUNTERS]; 62 | gpioSettingsStruct gpioSettings; 63 | }; 64 | 65 | struct websettings_t { 66 | String name; 67 | String value; 68 | struct websettings_t *next; 69 | }; 70 | 71 | void setupConditionals(); 72 | int getFreeMemory(void); 73 | char *getUptime(void); 74 | void setupWifi(settingsStruct *heishamonSettings); 75 | int getWifiQuality(void); 76 | int getFreeMemory(void); 77 | void ntpReload(settingsStruct *heishamonSettings); 78 | 79 | void log_message(char *string); 80 | int8_t webserver_cb(struct webserver_t *client, void *data); 81 | void getWifiScanResults(int numSsid); 82 | int handleRoot(struct webserver_t *client, float readpercentage, int mqttReconnects, settingsStruct *heishamonSettings); 83 | int handleJsonOutput(struct webserver_t *client, char* actData, char* actDataExtra, char* actOptData, settingsStruct *heishamonSettings, bool extraDataBlockAvailable); 84 | int handleFactoryReset(struct webserver_t *client); 85 | int handleReboot(struct webserver_t *client); 86 | int handleDebug(struct webserver_t *client, char *hex, byte hex_len); 87 | void settingsToJson(JsonDocument &jsonDoc, settingsStruct *heishamonSettings); 88 | void saveJsonToFile(JsonDocument &jsonDoc, const char *filename); 89 | void loadSettings(settingsStruct *heishamonSettings); 90 | int getSettings(struct webserver_t *client, settingsStruct *heishamonSettings); 91 | int handleSettings(struct webserver_t *client); 92 | int saveSettings(struct webserver_t *client, settingsStruct *heishamonSettings); 93 | int settingsReconnectWifi(struct webserver_t *client, settingsStruct *heishamonSettings); 94 | int settingsNewPassword(struct webserver_t *client, settingsStruct *heishamonSettings); 95 | int cacheSettings(struct webserver_t *client, struct arguments_t * args); 96 | int handleWifiScan(struct webserver_t *client); 97 | int showRules(struct webserver_t *client); 98 | int showFirmware(struct webserver_t *client); 99 | int showFirmwareSuccess(struct webserver_t *client); 100 | int showFirmwareFail(struct webserver_t *client); 101 | -------------------------------------------------------------------------------- /Heishamon-case-not-used-old-version.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Egyras/HeishaMon/c5fa066f557b739761b5e91c0dcae68711c91284/Heishamon-case-not-used-old-version.stl -------------------------------------------------------------------------------- /Heishamon-case-small-version-with-opentherm.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Egyras/HeishaMon/c5fa066f557b739761b5e91c0dcae68711c91284/Heishamon-case-small-version-with-opentherm.stl -------------------------------------------------------------------------------- /Integrations/Domoticz/README.md: -------------------------------------------------------------------------------- 1 | # Heishamon in Domoticz 2 | 3 | There are two options to integrate HeishaMon into Domoticz. You can choose for the domoticz plugin or a nodered flow. The domoticz plugin is plug-and-play but the nodered flow will allow you to more fine tune your system to your needs. 4 | 5 | 6 | ## Plugin option 7 | 8 | A domoticz plugin (https://github.com/MarFanNL/HeishamonMQTT) is available which, once installed, will create the necessary device and will talk to mqtt for you. 9 | 10 | 11 | ## Nodered option 12 | 13 | Prerequisite: 14 | - Domoticz with mqtt setup 15 | - node-red with mosquitto (optionally with https://flows.nodered.org/node/node-red-contrib-influxdb installed) 16 | - Working PCB with Heishamon firmware installed 17 | 18 | 19 | Installation instructions: 20 | 21 | In Influx: 22 | - create a database called "Panasonic" (go to SSH console -> typ "influx" -> typ "create database Panasonic" -> typ "show databases" and see if Panasonic is listed) 23 | 24 | In Node-red: 25 | - import the 'json' file 26 | - adjust the IDX values in the Node-Red function 'global setup' to the IDX values of your install. 27 | - note: you have to adjust values under "SensorMapping" (values from Panasonic to Domoticz) and "ActionMapping" (Domoticz commands to Panasonic). These IDX values can be the same. 28 | - If nodered is on other server then the influx or MQTT server then change these IP addresses in the outgoing and incoming nodes. 29 | - If you are not using influx out open the "influx out" node and disable it (bottom of the screen) 30 | 31 | For example create these devices in Domoticz: 32 | - Create the following dummy sensors in Domoticz and use the IDX values in the corresponding lines in the setup node. 33 | Temperature: 34 | - Outlet 35 | - Inlet 36 | - Outdoor 37 | Percentage: 38 | - Pumpspeed 39 | - Compressor frequency 40 | Counter: 41 | - startstops 42 | - working hours 43 | 44 | - Create the following switches: 45 | - On Off switch (switch heatpump on/off) 46 | - Selector switch (to set the silent mode: Off, silent 1, Silent 2, Silent 3) 47 | - Thermostat Setpoint (to set the heatpump setpoint or temperature shift) 48 | 49 | -------------------------------------------------------------------------------- /Integrations/Home Assistant/README.md: -------------------------------------------------------------------------------- 1 | ## Integration 2 | 3 | See https://github.com/kamaradclimber/heishamon-homeassistant/ 4 | 5 | 6 | ## or using manual declaration of entities 7 | 8 | 1. Create or copy file heishamon.yaml in directory /config/packages ( if directory not exist , create it) 9 | 2. Open file configuration.yaml in directory /config ,and check for lines: 10 | 11 | ``` 12 | homeassistant: 13 | packages: !include_dir_named packages 14 | ``` 15 | If not exists ,add them. 16 | 17 | 3. Go to Configuration / Server Control ,and first check configuration , if it is ok Restart HA. 18 | -------------------------------------------------------------------------------- /Integrations/Openhab2/panasonic.items: -------------------------------------------------------------------------------- 1 | //Panasonic Heat Pump// 2 | String panasonic_heat_pump_controller "State [%s]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/LWT:state:default]"} 3 | Number panasonic_heat_pump_HeatShiftTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Z1_Heat_Request_Temp:state:default]"} 4 | Number panasonic_heat_pump_CoolShiftTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Z1_Cool_Request_Temp:state:default]"} 5 | Number panasonic_heat_pump_TankSetTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/DHW_Target_Temp:state:default]"} 6 | Number panasonic_heat_pump_HCurveOutHighTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Z1_Heat_Curve_Target_High_Temp:state:default]"} 7 | Number panasonic_heat_pump_HCurveOutLowTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Z1_Heat_Curve_Target_Low_Temp:state:default]"} 8 | Number panasonic_heat_pump_HCurveOutsLowTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Z1_Heat_Curve_Outside_Low_Temp:state:default]"} 9 | Number panasonic_heat_pump_HCurveOutsHighTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Z1_Heat_Curve_Outside_High_Temp:state:default]"} 10 | Number panasonic_heat_pump_ActWatOutTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Main_Outlet_Temp:state:default]"} 11 | Number panasonic_heat_pump_ActTankTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/DHW_Temp:state:default]"} 12 | Number panasonic_heat_pump_ActOutTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Outside_Temp:state:default]"} 13 | Number panasonic_heat_pump_WatOutTarTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Main_Target_Temp:state:default]"} 14 | Number panasonic_heat_pump_RoomTherTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Room_Thermostat_Temp:state:default]"} 15 | Number panasonic_heat_pump_InletTemp "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Main_Inlet_Temp:state:default]"} 16 | Number panasonic_heat_pump_Floor_HeatDelta "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Heat_Delta:state:default]"} 17 | Number panasonic_heat_pump_Floor_CoolDelta "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Cool_Delta:state:default]"} 18 | Number panasonic_heat_pump_Tank_HeatDelta "Temp [%.0f °C]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/DHW_Heat_Delta:state:default]"} 19 | Number panasonic_heat_pump_PumpFlow "Flow [%.2f L/min]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Pump_Flow:state:default]"} 20 | Number panasonic_heat_pump_walve_state "walve_state" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/ThreeWay_Valve_State:state:default]"} 21 | Number panasonic_heat_pump_defrost_state "Defrost" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Defrosting_State:state:default]"} 22 | Number panasonic_heat_pump_CompFreq "Frequency [%.0f Hz]" (HeatPump) {mqtt="<[broker:panasonic_heat_pump/main/Compressor_Freq:state:default]"} 23 | Number panasonic_heat_pump_OperatingTime "Time [%.0f h]"