Compare commits

...

204 commits

Author SHA1 Message Date
Ray Jones f041cf8cad Final release V3.2.2 2020-09-16 14:46:54 +10:00
Ray Jones d0a5da308d IDF PATCH TO SOLVE RMT CRASH WEHN SAVING TO FLASH 2020-06-30 05:46:31 +10:00
Ray Jones a9e0a1e60d Made release version V3.2.1 2020-06-22 12:15:57 +10:00
Ray Jones ef04489fa6 Allowed web update of beta version to release of same base version 2020-06-19 16:49:40 +10:00
Ray Jones f18cfbf2e5 Manual selective Merge from bleeding edge, pulling in 433MHz, new HC05 and NV storage semaphore fix. 2020-06-19 11:24:44 +10:00
Ray Jones 2548191173 V3.2.0 release 2020-05-21 07:42:15 +10:00
Ray Jones 21e17d1a2b Fix for incoming MQTT status 1
Use pull up resistor for new HC-05 BT modules rx data
2020-05-21 07:27:06 +10:00
Ray Jones 775f235ba8 Added Stop/Start thermostat mode
FuelUsage & FuelRate added as basic MQTT status topics
2020-05-13 10:37:31 +10:00
Ray Jones 24d8a4a7f1 Added timer retry according to temperature being denied in the past 2020-05-09 19:17:21 +10:00
Ray Jones 7b36aa27f5 Tidy up after check pull 2020-05-07 11:51:15 +10:00
Ray Jones 4b3951b465 BUG FIX: signed 16 bit issue reporting altitude over JSON 2020-05-07 10:12:20 +10:00
Ray Jones 97f3433158 BIG FIXES: External thermostat start denied if internal thermostat too high
Pump priming from web page only worked once - was because prime command was never released from heater.
2020-05-06 10:41:26 +10:00
Ray Jones 3129a88cb9 Pretty stable with https library BUT #ifdef'd out actual https usage is is very temperamental ATM. 2020-05-03 21:59:56 +10:00
Ray Jones c74f0a76eb Merge branch 'WebAuth' into SSLtrials
Conflicts resolved:
	src/Afterburner.cpp
	src/WiFi/BTCWebServer.cpp
	src/WiFi/BrowserUpload.cpp
	src/cfg/BTCConfig.h
2020-04-26 19:52:00 +10:00
Ray Jones b75254220c Allow entry of no password 2020-04-26 19:28:31 +10:00
Ray Jones 9ff2d9410b Split websocket handling into a task
Read all added to BME-280 (MariusZ)
New security menu in debug/telnet
2020-04-26 16:15:08 +10:00
Ray Jones 5cdc5c95a5 Moved Blue Wire Comms to a separate task 2020-04-25 09:23:16 +10:00
Ray Jones 28bfb28ff6 Adding web authorisation 2020-04-22 16:42:24 +10:00
Ray Jones baf8678e99 Added some FreeRTOS tasks to avoid blocking issues - still very unreliable 2020-04-22 16:21:24 +10:00
Ray Jones b58ed90432 Found websocket write was blocking, returning 0, leading to WD reboot. Need to think of proper fix 2020-04-20 13:39:39 +10:00
Ray Jones 67998747d7 Added DemandManager, removing TimerManager from direct temperature demand control aspects
Likewise moved demand adjustments into DemandManager.
2020-04-11 18:49:52 +10:00
Ray Jones 9839571893 Added support for injecting Fixed Hz demands if a timer start has a defined temperature.
Uses normal range for fixed Hz.
2020-04-11 07:51:25 +10:00
Ray Jones 4625f98cf3 Core panic in TxManage, concluding gate in timer callback - using digitalwrite is BAD @ ISRL!!!
Now use FreeRTOS queue to pass the actual event down.
2020-04-09 06:57:26 +10:00
Ray Jones 0ed7ba7e59 Fixed NULL dereference in asyncHTTPrequest - causes core panics if STA but no internet/server unreachable 2020-04-08 20:17:40 +10:00
Ray Jones 4eddcd0f1e STA only mode
Fixed MQTT topic prefix
2020-04-08 07:51:52 +10:00
Ray Jones 3e3ef7d2f2 AsyncTCP touch 2020-03-31 19:48:03 +11:00
Ray Jones 9c100f1954 Added Fuel Reset GPIO input option 2020-03-31 19:46:25 +11:00
Ray Jones 8ec438e02a Added excess fuel usage shutdown feature 2020-03-30 16:17:54 +11:00
Ray Jones 8b8aaf0024 Timer Temperature support added
Desired temperature requests are now managed via TimerManager to allow timer override of desired temperature.
Bug fix: crash checking for new firmware if no STA connection
Suppression of GPIO JSON if no or limited GPIO capability is installed.
2020-03-29 13:59:13 +11:00
Ray Jones 87b1704335 Added OLED and JSON Web Content Update functionality 2020-03-25 20:28:12 +11:00
Ray Jones 1d80e34c4b Added web content download feature.
Need to incorporate into OLED menus etc.
2020-03-24 21:14:41 +11:00
Ray Jones 4986a4d741 Assortment of tweaks and fixes
New Features:
GPIO "Run" status output (not standby)
RSSI of STA connection
STA gatewayIP
Only run as "active" controller when changes to fuel mixture etc for a short while.
Timed moderation added for frequently changing JSON vars
Altitude & Humidity via JSON
JSON reboot (mainly for MQTT clients)

Bug Fixes:
Cyclic not enabled when frost start
LVC holdoff added for "starting car" situation
Better handling of string and float NV Storage defaults
FrostRise limits  1-30 now 0-30
Handle spaces in SPIFFS file uploads
2020-03-23 16:54:15 +11:00
Ray Jones 3ca3e633ae Added getch the to our TelnetSpy overload. This adds the logic to add a LF if only CR is sent by a terminal package 2020-01-15 17:52:43 +11:00
Ray Jones 06d78860ca Bug fix: Factory default would not save 2020-01-15 07:55:57 +11:00
Ray Jones 41d43813b7 V3.1.8 2020-01-13 19:58:55 +11:00
Ray Jones 7e1a4940ac Added BME280 humidity and altitude information
Can start heater if high humidity
Altitude reported to heater per BMP180 in OEM controllers.
lowered min Hz limit to 500
2020-01-13 19:48:32 +11:00
Ray Jones 083fb63764 BUG FIX: always showing offset against DS18B20 in temp sensor role screen 2020-01-09 12:50:54 +11:00
Ray Jones 88cf18bfcf BUG FIX: insufficient wait time after OEM controller data packet, bad calc of start time :-( 2020-01-07 12:30:13 +11:00
Ray Jones af1ab021a4 Renamed to ABMQTT.cpp/.h 2020-01-06 06:11:22 +11:00
Ray Jones 194cc08ac9 Case Sensitive issue "ABmqtt"/"ABMqtt" -> "ABMQTT.h" 2020-01-05 08:46:46 +11:00
Ray Jones f5d72e2ac8 Using asyncHTTPrequest for version update check, synchronous method for actual update.
Released and tagged as V3.1.7.4 BETA
2020-01-04 18:13:40 +11:00
Ray Jones 69155f8e45 Stabilise using AsyncTCP to scrape FOTA JSON file.
Need to establish WTF "closed_slots" in AsyncTCP are all about, especially the bad indexes that fly about leading to LWIP crashes.
2019-12-15 17:58:11 +11:00
Ray Jones c76490481d Bug fixes:
Telnet spy would not work in AP only mode
LVC would not allow start when in warning mode, and LVC warning always started at 12/24V
Added "No GPIO" option for new boards with C6 fitted as a 0R
2019-12-06 21:12:56 +11:00
Ray Jones c9298656fa Tx gate now terminated via a HW timer callback. Using max priority task for SW watchdog. 2019-11-22 21:30:45 +11:00
Ray Jones c649517805 BUG FIX: Introduced an E-07 issue if an OEM controller was plugged in
- was due to vTaskDelay at end of loop() - now only delays if OEM is NOT detected.
2019-11-21 20:32:54 +11:00
Ray Jones 6fb7b9d608 Added UIEditScreen class to standardise the save&confirm behaviour.
Bug fix in body temperature sensor < 0
2019-11-21 19:25:14 +11:00
Ray Jones eb2e2d4305 bug fix of rowsel in ds18b20 screen 2019-11-11 18:59:49 +11:00
Ray Jones d8e71eebc1 Added Frost Mode setup screen, sub-classed NVstore confirm behaviour 2019-11-10 15:44:54 +11:00
Ray Jones 53430d3fa0 frost icon 2019-11-01 09:25:58 +11:00
Ray Jones 7081391f63 Added core frost functionality 2019-11-01 09:24:58 +11:00
Ray Jones f2af9c3fda Added under/over temperature threshold for GPIO outputs 2019-10-30 21:48:25 +11:00
Ray Jones 96b3cecdb0 Updated AsyncTCP library - had bad DNS handling if name not resolvable (null pointer dereference) 2019-10-28 17:32:16 +11:00
Ray Jones b1cee63ec3 Added ABTelnetSpy derived class modules 2019-10-27 16:37:12 +11:00
Ray Jones 4138d0b2f5 Blocked debug messages whilst getting other strings. STA only retries if a SSID is defined 2019-10-27 15:24:54 +11:00
Ray Jones 5efce879ce Quietened down debug reporting when MQTT or Bluetooth debug menus active.
Single debug report of one wire searches (init only typ.)
2019-10-27 14:25:40 +11:00
Ray Jones f330d812e6 Added JTAG use defines for ESP PROG debug 2019-10-27 11:02:49 +11:00
Ray Jones 8893abb575 tidy up 2019-10-20 20:19:27 +11:00
Ray Jones 2e25ad3da4 Fixed role ordering in NV for DS18B20 probe offsets
Replaced ` with clean degree symbol in standard font & arial 8
Removed temp offset from fuel cal screen
GUI alignment tweaks to avoid cutoffs
Better handling of single DS18B20 with BME280
Added bounds limits to Exponential Mean
Sorted inheritance from CSensor properly
2019-10-19 09:58:19 +11:00
Ray Jones aabe6a54b3 Stabilised BME280 with DS18B20 coexistence 2019-10-18 12:55:16 +11:00
Ray Jones 7c43523d51 V3.1.5 bootloader update 2019-09-26 06:34:30 +10:00
Ray Jones ab246244c9 Merge branch 'Branch_V3BoardDetect' 2019-09-25 19:39:02 +10:00
Ray Jones af34331401 Dig Only V3 PCB, Fixed Hz setting reporting bug fix 2019-09-25 19:38:19 +10:00
Ray Jones 112628f103 Tidy up 2019-09-25 17:27:43 +10:00
Ray Jones 573ebf3e3b Added auto save of single DS18B20 serial number 2019-09-22 14:46:39 +10:00
Ray Jones 8fb1981552 Added Temp Probe selection screen, mapping sensors to user preferences 2019-09-22 09:03:42 +10:00
Ray Jones de9417ff73 Tidied JSON/MQTT topic command decode into UtilClasses.cpp 2019-09-21 09:58:51 +10:00
Ray Jones 6e86571a19 Merged branch 'VerboseMQTTout'
Resolved Conflicts:
	src/Afterburner.cpp
	src/Utility/BTC_JSON.cpp
2019-09-21 08:11:36 +10:00
Ray Jones bf537d1ac5 MQTT can now accept any cmd topic that matches the JSON names 2019-09-20 23:00:27 +10:00
Ray Jones 095797f8b0 . 2019-09-19 19:23:59 +10:00
Ray Jones b2cc6ff36d V3.1.4 2019-09-19 19:04:09 +10:00
Ray Jones c51b18dd36 Added password hold option 2019-09-17 20:07:57 +10:00
Ray Jones 3a70970356 Added menu mode selection menu 2019-09-17 08:30:49 +10:00
Ray Jones 36d1b06ba2 Adding DHT22 library 2019-09-15 12:55:02 +10:00
Ray Jones f93e5d7628 Add basic menu Modes 2019-09-15 12:51:51 +10:00
Ray Jones d30536e939 V3.1.3 - Bug fix not disabling WiFi correctly 2019-09-12 06:32:21 +10:00
Ray Jones 3a810d6eea Tidied Repeating timer icon 2019-09-08 11:56:22 +10:00
Ray Jones fa36236948 V3.1.2 bootload 2019-09-08 11:38:45 +10:00
Ray Jones ac5fdc5dfd V3.1.2 -
AM/PM selection in clock setup menu.
Extra MQTT JSON IDs added.

Filtered No Heater JSON.
2019-09-08 10:14:36 +10:00
Ray Jones 583a4881cd Added AM/PM annunciators to clock for 12hr mode
Added last will to MQTT connection
Condensed no heater timeouts with default screen
2019-09-07 23:48:46 +10:00
Ray Jones 9fbb6e8dfc Shifted MQTT telnet setup into a separate module.
Fixed addCRC script for > V3 python
2019-09-07 18:28:21 +10:00
Ray Jones 77dada9d6b BUG FIX: Fuel gauge reset via web page
NEW FEATURE: MQTT status screen
2019-09-04 20:59:01 +10:00
Ray Jones 13fb3f715a Un commented the code that restores an STA connection 2019-09-02 08:22:33 +10:00
Ray Jones 8a237059fd Added JSON driven watchdog 2019-09-01 17:35:12 +10:00
Ray Jones 3e4ce429c7 BUG FIX: bad clientID due to bad MQTT library - causes disconnects with multiple AB's on one broker!
IMPROVEMENT: MQTT reconnect implemented.
2019-09-01 14:43:00 +10:00
Ray Jones fdf4e9af99 Set version to V3.1.0 - MQTT!!! 2019-08-31 17:41:01 +10:00
Ray Jones 61e246f6f1 telnet menu to setup MQTT. JSON now pushed over MQTT - typ. topic name: Afterburner/JSONout 2019-08-31 17:34:56 +10:00
Ray Jones 253bc3f728 Added MQTT topic for controller to NV store.
Found PubSubClient is blocking, causing WD reboots
2019-08-30 20:08:54 +10:00
Ray Jones f6f721bd8a Got basic MQTT session working to test.mosquito.org :-) 2019-08-27 23:09:07 +10:00
Ray Jones c79522233c Added Stop function to GPIO input #1 (eg CO sensor with Ext Thermostat 2019-08-27 20:35:21 +10:00
Ray Jones 08a39a26f7 Added countdown to detailed GUI for external thermostat shutdown feature 2019-08-27 06:13:01 +10:00
Ray Jones 7853102a4d Added external thermostat time function to GPIO setup screen 2019-08-26 08:41:44 +10:00
Ray Jones e7bac339b5 Implemented functionality to start & stop heater according to external thermostat input 2019-08-26 06:37:41 +10:00
Ray Jones f5a8c3c11e BUG FIX: GPIO2 set for external thermostat sent dT as the Greek 'd' in the JSON - BAD - broke websocket 2019-08-19 05:33:07 +10:00
Ray Jones a491db257a Proper binary in bootload 2019-08-11 09:50:17 +10:00
Ray Jones 79b6c06a2a Added AP SSID/password configuration via debug port 2019-08-10 21:45:28 +10:00
Ray Jones d7e083b837 Board detect bug fix. New icons for GPIO setup/status 2019-08-10 15:57:46 +10:00
Ray Jones 4873fa8c71 Split GPIO so each pin's function is defined individually.
Adjusted DS18B20 timing to match Maxim's recommended values.
2019-08-09 06:13:02 +10:00
Ray Jones 48a0254f13 Can now define the operation mode for each GPIO line individually.
Need to test actual functionality, GUI OK.
2019-08-07 22:04:20 +10:00
Ray Jones 10db95733f Added external thermostat via GPIO in 2. Want to change how GPIO pins are defined.
Modded code to only allow single DS18B20 - getting funny ROM SEARCH lock ups...
Set mini temp sample interval to 750ms, as per data sheet for 12bit DS18B20
2019-08-07 18:59:30 +10:00
Ray Jones e205119b24 Added trap for skipping directly to suspend if already over temperature with cyclic mode enabled.
Otherwise heater starts then runs stop cycle immediately!
2019-08-04 11:15:41 +10:00
Ray Jones 1c314e14f2 removed debug prints of TempCurrent - grrrrr 2019-08-04 08:23:54 +10:00
Ray Jones 2a788cb2d0 Fixed rounding issue of TempCurrent in JSON data, always 0.1 low 2019-08-04 08:19:59 +10:00
Ray Jones 27b988c895 Fixed referral to test FOTA page 2019-08-03 20:47:19 +10:00
Ray Jones e5e0f87e0b Tidy of animation counts in screen header - was delaying appearance of battery icon 2019-08-03 19:52:37 +10:00
Ray Jones 08d0307fc8 BUG FIX: Web update was broken due to watchdog timeout - added onProgress to FOTA - all good now
Returned to compact timer icon, press centre button to see start/stop times in base menus
Version info screen refactored to show available version number
New splash screen now presented upon display for a short time after upload or rename to /splash.bmp
2019-08-03 12:42:49 +10:00
Ray Jones ac091fa6d8 Added ability to upload custom splash ScreenFlowV3.dia.
Added 4th board type - GPIO disabled on V2.0 PCB - install 0R in C6, leave other bits out.
2019-08-01 22:57:18 +10:00
Ray Jones 945d9c88b7 Revised CRCengine to include all bytes uploaded - CRC of everything should be 0! 2019-07-31 06:27:04 +10:00
Ray Jones 8daf555950 Validation CRC now generated by python script 2019-07-30 22:59:51 +10:00
Ray Jones 1b3b478a49 Reset to original Arduino min_spiffs partition layout.
Fixed a residual screen refresh issue with cyclic enabled and max temp dialed up - marker stuck.
SPIFFS upload added to bootload.zip COM.bat
2019-07-30 19:21:55 +10:00
Ray Jones a52143479f Fix of residual screen content following browser updates of SPIFFS files. 2019-07-28 20:59:26 +10:00
Ray Jones c1207e66ef Extreme makeover to timer manager, now properly shows one shot next day timers in timer chart.
Added cursor showing time of day on Timer chart.
2019-07-28 17:40:12 +10:00
Ray Jones f154580eb2 Tidied up timer setup screen
OTA uploads now have a bar graph!
2019-07-28 11:37:39 +10:00
Ray Jones 6c21a9c6a6 Titled Timer screen - lost std header
Added missing source files
2019-07-28 09:07:29 +10:00
Ray Jones d563cb0c8a MASSIVE rework of the menu structure 2019-07-28 00:28:39 +10:00
Ray Jones a7348fdbf5 Decoding HC-05 MAC address 2019-07-27 12:47:16 +10:00
Ray Jones dfa60eb491 added cable compensation to LVC warning threshold 2019-07-27 08:50:09 +10:00
Ray Jones ca0e763da6 Added Hour Meters screen 2019-07-26 23:12:00 +10:00
Ray Jones d2116fc18c Cleaner hourmeter handling using a new class for each counter.
Added a warning animation to LVC, ether <12V, or 0.5V > LVC if that result is over 12V
2019-07-26 22:13:46 +10:00
Ray Jones f86ae7cffb tidied Hourmeter class, staged NV changes to write in correct time slot 2019-07-26 06:39:56 +10:00
Ray Jones 1dbfa67163 Storing actual runtimes to NV store at heater off, resetting intermediates at same time.
Improved restart behaviour of persistent variable handling
2019-07-25 22:31:31 +10:00
Ray Jones 2084c7d60c added BootInit flag to RTC store - used for persistent vars init after OTA updates 2019-07-25 21:27:57 +10:00
Ray Jones c621f7078c Moved src/libraries to /lib - '.a' files now get generated by PIO for each library. 2019-07-25 17:40:23 +10:00
Ray Jones 9c338fa74c Main skeleton of Hourmeter in place 2019-07-25 06:06:47 +10:00
Ray Jones 92283a3e0d Added module files for fuelgauge, RTCStore, HourMeter 2019-07-24 19:25:07 +10:00
Ray Jones 204007401b tweaked reboot message timeouts for /update & /reboot 2019-07-23 22:56:04 +10:00
Ray Jones 04de63b07e Added empty Afterburner.ino file - well a file full of comments 2019-07-23 22:44:47 +10:00
Ray Jones 8ebf6dbf3e Refactored directory hierarchy to regain some linker command line space in PIO 2019-07-23 22:32:36 +10:00
Ray Jones cb79fd5dd0 BUG FIX - E-01 fired upon reboots with premature low volt detection
Improvement - /update and /reboot now have a post event status sequence during reboot.
2019-07-23 21:11:29 +10:00
Ray Jones db3343d362 Bug Fix: bounds checks for LVC did not allow 0 2019-07-23 06:15:18 +10:00
Ray Jones 672645c59a Merge branch 'FuelGauge' 2019-07-22 21:10:15 +10:00
Ray Jones cf41285052 added new icons/MiniThermo.bmp 2019-07-22 21:07:10 +10:00
Ray Jones dca26680b4 cancel cyclic mode upon error fail 2019-07-22 20:58:36 +10:00
Ray Jones d6bba90c84 LVC JSON now proper floating point.
Tidied screen dribbles in priming menu
2019-07-22 06:30:08 +10:00
Ray Jones 06e69acc77 Added Low Volt Cutout, Temperature probe offset
Tarted up fuel mixture adjust screen
2019-07-21 21:17:54 +10:00
Ray Jones dd5e62c8cb Rework priming menu, can now reset fuel gauge. JSON added for fuel usage & cal. 2019-07-20 16:08:43 +10:00
Ray Jones 04ae988d2d . 2019-07-20 06:53:12 +10:00
Ray Jones a543ba0748 Tidied browser update by adding new browserupload class.
Adding RTC register storage for frequent NV updates (fuel gauge, desired temp etc)
2019-07-18 22:28:40 +10:00
Ray Jones e50d93bb8c Using RTC registers to store fuel gauge.
Added BrowserUpload class
2019-07-18 22:25:28 +10:00
Ray Jones 77ac324d64 Added SPIFFS upload error detection and feedback to browser
Added Time/Date responses
2019-07-17 19:35:34 +10:00
Ray Jones 4d6ab5b280 Single shot SQuery (stops JSON Time & UpTime constantly being sent).
Working on SPIFFS upload abort if out of space....
2019-07-16 06:29:23 +10:00
Ray Jones 16ee16f97f Added support for .gz compressed SPIFFS files.
Using wrapper for millis() via library --wrap option, returns xTaskGetTicksCount() instead of the very dubious int64_t/1000 of default millis(), especially when it gets BIG.
2019-07-15 19:56:36 +10:00
Ray Jones 1f28bb7d5d Added JSON IP query parameters 2019-07-11 22:03:27 +10:00
Ray Jones de1eb48f78 Added CRC generation code 2019-07-11 18:59:40 +10:00
Ray Jones b6b0c7afbd stylish /update & /formatspiffs 2019-07-11 18:55:31 +10:00
Ray Jones 8dd5dc662e Added extra CRC checking to OTA 2019-07-09 22:19:21 +10:00
Ray Jones 278d40af33 big dependency tidy up 2019-07-07 17:18:38 +10:00
Ray Jones 66f10445a4 Update .gitignore 2019-07-06 23:51:20 +10:00
Ray Jones 2f38a33984 Omitted DataFilter.cpp &DataFilter.h 2019-07-06 23:48:38 +10:00
Ray Jones 1b4b6699c5 Added exponential mean to heater data.
Replaced char with int8_t - damn thing was unsigned!
Likewise uint8_t for unsigned char
Rework of webserver inbuilt management functions cross linked, work well
2019-07-06 23:46:20 +10:00
Ray Jones c20b309184 Added CyclicOn, CyclicOff, CyclicTemp JSON Removed UserSettings subset setters/getters
BOUNDS checking on JSON inputs
2019-07-03 23:01:36 +10:00
Ray Jones 6d7af0e010 Bug fix of feedback over JSON of TempDesired when in Fixed Hz mode.
Introduced when demandDegC/demandPump split was added to fix Cyclic shutdown on low Hz demands.
2019-07-03 20:28:00 +10:00
Ray Jones 40c0a72c77 Added shell script to create symbolic links for Linux Arduino builds 2019-07-02 22:08:49 +10:00
Ray Jones 4330d2eac5 batch file for symbolic links fixed 2019-07-02 21:31:40 +10:00
Ray Jones fcd15ddb34 Removed symbolic links in Arduino build path.
These should be built after initially pulling the repo, then life is good.
2019-07-02 21:21:41 +10:00
Ray Jones 6b814e70d9 NVstorage.h fix up 2019-07-02 20:22:14 +10:00
Ray Jones 657bec98e7 Merged owa and ds18b20 libraries - weird include issues under Linux? 2019-07-02 20:18:44 +10:00
Ray Jones 0378e733ef font rename 2019-07-02 19:17:24 +10:00
Ray Jones 592ace0f0a and more freertos 2019-07-02 19:02:28 +10:00
Ray Jones 4491da1f2f more freertos vs FreeRTOS 2019-07-02 19:00:07 +10:00
Ray Jones d247d14945 fixups of FreeRTOS dir to freertos 2019-07-02 18:49:40 +10:00
Ray Jones 471a423a19 An intensive include directory clean up (case / system paths) hopefully 99% there for Linux... 2019-07-02 18:27:20 +10:00
Ray Jones e6b8365f09 Moved all libraries inside repository - this ensures all builds use the same libraries. 2019-07-01 20:46:08 +10:00
Ray Jones 8d143c03a5 Added Windows symbolic links so an Arduino project can parasite off the superior PlatformIO paths :-)
Adjusted JSON ThermostatOvertemp to be 0,2,3,4 etc.
2019-06-30 22:39:40 +10:00
Ray Jones a435aed47d gitignore additions 2019-06-30 16:49:18 +10:00
Ray Jones 129631c82a Converted to Platform IO friendly project, still works with Arduino provided you rename Afterburner.cpp to Afterburner.ino 2019-06-30 16:44:50 +10:00
Ray Jones f718611bd6 HTML'd up the inbuilt helper web pages /formatspiffs and 404 handling, adds next steps required etc
Added inbuilt /spiffs webpage to show WTF is stored in there, and usage.
Added HTML file test before attempting to send. This would hang when SPIFFS gets corrupted causing WD reboot.
2019-06-30 10:37:24 +10:00
Ray Jones 924a079fb2 Using new fantastic RMT based library for DS18B20, banished issues with dodgy readings from sensor.
Persistent variables now used for temperature, pump and cyclic mode enabled settings (not NV)
NV save is now staged, so it can be performed at an appropriate time, after reading DS18B20!
JSONpack, instead of lame JSONloose to allow single line JSON output
2019-06-29 18:08:37 +10:00
Ray Jones eef4365a83 First build under Platformio. SEEMS to have improved the 10 second timeout in websocket.
Most significant change was moving BlueWireSerialPort variable in TxManage.h .....
Secondary was a few operator= were not returning *this ....
2019-06-27 06:04:24 +10:00
Ray Jones 52ecbcedae report SPIFFS usage upon boot 2019-06-25 17:49:07 +10:00
Ray Jones 7210302e5e Bug Fix - did not show timers unless when an update was available!
Bug Fix - Timer repeat icon had X.Y dimensions reversed.
Bug Fix: Fixed factory default was ineffective!
Introduced a hold off to avoid E-07 unless persistent.
2019-06-16 20:37:25 +10:00
Ray Jones 7081b957f1 Bug Fix - E-07 due to a delayed heater response would stop heater if cyclic mode was enabled 2019-06-16 18:13:16 +10:00
Ray Jones 19b17af925 Less cluttered cyclic mode brackets on detailed GUI 2019-06-16 09:47:38 +10:00
Ray Jones ce8299609b Split PumpDemand and Temperature demands so Fixed Hz mode works cleanly, especially with Linear Hz thermostat and Cyclic mode.
Cyclic mode, if enabled, is now shown on detailed screen, bracketing its range
Shifted helpers.h into src/Utility - made far more logical sense!

Fancy pants slash screen :-D
2019-06-16 09:09:29 +10:00
Ray Jones a53d6eabd0 removed most helper functions from NVstore, now pass in/out cal structures. Fixed some bad NV stores 2019-06-06 11:32:43 +10:00
Ray Jones cfdedc0d7c Now capture transient events on GPIO inputs for JSON output 2019-06-05 06:36:29 +10:00
Ray Jones dafd7ba856 Fixed NV storage issue.
Adding GPIO JSON
2019-06-05 06:15:12 +10:00
Ray Jones 811c15093c Moved FOTA to local library to deal with 2 bugs, OTA reported on OLED according to source. 2019-06-03 06:34:45 +10:00
Ray Jones f4a3ce45bb Condensed NV GPIO params into a struct. Improved GPIO info screen, showing disabled modes 2019-06-02 22:47:35 +10:00
Ray Jones 200b928af6 Tidied animation for wifi activity and mode indications when no traffic 2019-06-02 19:19:08 +10:00
Ray Jones 0a6171ae8b Bug Fix: was not calling into ESP32 non volatile load /save etc - lack of virtual functions! 2019-06-01 18:03:38 +10:00
Ray Jones 4f9a77486a Refactored bitmap definitions so they are now held in const BITMAP_INFO structures 2019-06-01 10:18:31 +10:00
Ray Jones 18927d758a Implemented TQuery to greatly reduce JSON traffic upon new client connections. 2019-05-30 20:31:34 +10:00
Ray Jones 7817b7f2e0 Direct access between GPIO setup and test screens, version info from priming screen 2019-05-29 18:01:51 +10:00
Ray Jones c83a0cc9c5 pushing upload file size via web socket so we can use an upload progress percent on OLED.
Tidied wifi traffic icons
2019-05-23 06:35:09 +10:00
Ray Jones 760aa2fc6f Improved end of file upload handling, added www icon to firmware update. 2019-05-22 21:08:38 +10:00
Ray Jones 21cf587798 Can push SPIFFS files now via the firmware upload browser form.
However only works as a flat file system for now...
2019-05-21 22:01:42 +10:00
Ray Jones 0572acaeca Animated update available on Version Info screen 2019-05-21 18:29:16 +10:00
Ray Jones 2ccd948001 Web update via OTA now under user control. Icon shows on header when an update is available.
Update can be commanded via the Version Information menu by pressing UP, CENTRE, UP. Prompt driven of course!
Removed Wifi Trigger pin - does not play nice with automatic COM port uploads!
Reverted to DS18B20 read from index 0 - allows plugging sensor in and re-discovery!
2019-05-20 22:09:59 +10:00
Ray Jones fc8eef73a6 Using websocket to get proper firmware upload byte count 2019-05-18 18:49:22 +10:00
Ray Jones da33a02844 Added SW watchdog 2019-05-17 16:08:35 +10:00
Ray Jones 843c382325 Omitted new NVCore.cpp/.h 2019-05-16 21:15:16 +10:00
Ray Jones a6540eb997 Added factory default via version menu.
WiFi credentials for SoftAP and web update now stored in NV storage.
NV Storage structures now handle load and save for their members
2019-05-16 21:12:29 +10:00
Ray Jones 60d84e3681 Merge branch 'JIM_mqttSettingsPage' into MQTTstore 2019-05-15 20:36:57 +10:00
Ray Jones 58f4631f72 Web update progress on OLED bug fix of runstate in index.html 2019-05-15 20:24:43 +10:00
James 9f0a046f0a Adding missing placeholders 2019-05-15 20:10:12 +10:00
Ray Jones c1bcc83e8b Proper std::string moderator, using mapped value for JSON output. Secure web upload with user/pass 2019-05-14 21:29:35 +10:00
Ray Jones 39aba4819f commented out missing ABMqtt header.
Fixed Index.html foibles of MQTT send.
64 byte limit in BT fixed.
2019-05-12 22:14:32 +10:00
Ray Jones 7bc681e848 Javascript fixups for James 2019-05-12 21:32:55 +10:00
Ray Jones cfa5ac857d Merge branch 'JIM_mqttSettingsPage' into MQTTstore 2019-05-12 20:20:56 +10:00
Ray Jones 04fab40742 Refactored string in JSON moderator - const char* are BAD AND EVIL in a std::map
MQTT parameter exchange via JSON and NV storage
2019-05-12 20:15:18 +10:00
James a36ef97af2 Settings for MQTT will now dissapear if not enabled in the web interface.
retrieve/save details should work once Ray creates nvRam hooks for the code:D
2019-05-12 19:14:03 +10:00
James 9072c6bb7a Added fields and javascript for MQTT settings (Web Page Only) 2019-05-12 11:47:46 +10:00
Ray Jones 38711533cd Updated .AIA file for BT Android app 2019-05-12 09:03:19 +10:00
Ray Jones e8f6b88aeb Quick fix: -20C -ve threshold for cyclic mode 2019-05-12 09:01:22 +10:00
1581 changed files with 133909 additions and 27913 deletions

18
.gitignore vendored
View file

@ -7,3 +7,21 @@
.vs
__vm
/Arduino/BTCDieselHeater/.vscode/*.json
.pio
.pioenvs
.piolibdeps
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
/.vscode/settings.json
/.vscode/extensions.json
Arduino/Afterburner/data/*
Arduino/Afterburner/src/*
/Altium
/Releases
/webdev
/case
/DieselHeaterV2.PcbDoc
/StandardResponse.txt
/HeaterHack-Tested.zip
/OTA_COM.txt

67
.travis.yml Normal file
View file

@ -0,0 +1,67 @@
# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
# several times a day < https://docs.platformio.org/page/ci/index.html >
#
# Documentation:
#
# * Travis CI Embedded Builds with PlatformIO
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
# < https://docs.platformio.org/page/ci/travis.html >
#
# * User Guide for `platformio ci` command
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
#
#
# Please choose one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
#
# Template #1: General project. Test it using existing `platformio.ini`.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio run
#
# Template #2: The project is intended to be used as a library with examples.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# env:
# - PLATFORMIO_CI_SRC=path/to/test/file.c
# - PLATFORMIO_CI_SRC=examples/file.ino
# - PLATFORMIO_CI_SRC=path/to/test/directory
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N

6
ABpartition.csv Normal file
View file

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x1E0000,
app1, app, ota_1, 0x1F0000,0x1E0000,
spiffs, data, spiffs, 0x3D0000,0x30000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x1E0000
5 app1 app ota_1 0x1F0000 0x1E0000
6 spiffs data spiffs 0x3D0000 0x30000

BIN
AppInventor/BT.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
AppInventor/BTsmall.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
AppInventor/BTverysmall.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,34 @@
/**********************************************************************
* This file is deliberately empty.
*
* It only exists to satisfy the Arduino IDE's perverse requirement that a
* .ino must live directly below a parent directory, with the same name.
*
* In this instance Afterburner\Afterburner.ino
*
* I seriously recommend you use PLatformIO with your favourite editor.
*
* The real source code for the entire project is linked to via a symbolic
* link to the ClonedRepo\src, lib & data directories.
*
* ie ClonedRepo\Arduino\Afterburner\src\src -> ClonedRepo\src (..\..\src)
* ie ClonedRepo\Arduino\Afterburner\src\lib -> ClonedRepo\lib (..\..\lib)
* ie ClonedRepo\Arduino\Afterburner\data -> ClonedRepo\data (..\..\data)
*
* A batch file is in this folder to create these links, please use it first.
*
* Whilst initially alarming that is .ino file is empty, the Arduino IDE
* happily creates the required executable :-)
*
* The REAL host of setup() and loop() resides in ClonedRepo\src\Afterburner.cpp
*
*
*****************************************************************************
*****************************************************************************
** **
** DUMP the Arduino IDE, and use PlatformIO. **
** Load the ClonedRepo path into PlatformIO. **
** Builds much faster and meshes well with decent programming editors :-) **
** **
*****************************************************************************
*****************************************************************************/

View file

@ -0,0 +1,5 @@
#!/bin/sh
mkdir src
ln -s ../../src src/src
ln -s ../../lib src/lib
ln -s ../../data data

View file

@ -0,0 +1,7 @@
rem mklink /H Afterburner.ino ..\..\src\AfterBurner\Afterburner.cpp
mkdir src
mklink /J src\lib ..\..\lib
mklink /J src\src ..\..\src
mklink /J data ..\..\data

View file

@ -0,0 +1,20 @@
TO WORK WITH ARDUINO IDE, EVERYTHING IN THIS FOLDER IS FAKE!
When you pull from gitlab, no symbolic links will be created.
You need to execute MakeSymLinks_Windows.bat from Explorer.
Arduino insists upon .ino for their projects, and the .ino
file name also has to match the parent directory name.
The BIG trick here is Afterburner.ino is empty - zilch, nada, nothing!
All the REAL source code lives via the src symbolic link.
The real core exists as a .cpp file: repo\src\Afterburner.cpp
Arduino\Afterburner\Afterburner.ino is EMPTY
Arduino\Afterburner\src\src links to repo\src\
Arduino\Afterburner\src\lib links to repo\lib\
Arduino\Afterburner\data links to repo\data
Ugggh. I hate Arduino IDE (and it's build environment!)

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,536 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<!-- <link rel="icon" href="data;,"> -->
<script>
var Socket;
function init() {
Socket = new WebSocket('ws://' + window.location.hostname + ':81/');
Socket.onmessage = function(event){
var heater = JSON.parse(event.data);
var key;
for(key in heater) {
console.log("JSON decode:", key, heater[key]);
switch(key) {
case "RunState":
if (heater[key] == 0) {
document.getElementById("myonoffswitch").checked = false;
document.getElementById("myonoffswitch").style = "block";
document.getElementById("onoffswitch").style.visibility = "visible";
} else if(heater[key] >= 7) {
document.getElementById("myonoffswitch").checked = false;
document.getElementById("myonoffswitch").style = "none";
document.getElementById("onoffswitch").style.visibility = "hidden";
} else {
document.getElementById("myonoffswitch").checked = true;
document.getElementById("myonoffswitch").style = "block";
document.getElementById("onoffswitch").style.visibility = "visible";
}
document.getElementById("RunString").style.visibility = (heater[key] == 5 || heater[key] == 0) ? "hidden" : "visible";
break;
case "ErrorString":
case "RunString":
document.getElementById(key).innerHTML = heater[key];
break;
case "PumpFixed":
case "TempCurrent":
document.getElementById(key).innerHTML = parseFloat(heater[key]).toFixed(1);
break;
case "TempDesired":
document.getElementById(key).value = heater[key];
var ValKey = key + 'Val'; // eg 'PumpMinVal'
document.getElementById(ValKey).innerHTML = heater[key];
break;
case "ErrorState":
document.getElementById("ErrorDiv").hidden = heater[key] <= 1;
break;
case "TempBody":
//The threshold levels for each bar to come on are: 21°C, 41°C, 61°C, 81°C, 101°C, 121°C
if(heater[key] > 120){
document.getElementById("TopBar").className = "active121";
}
else if(heater[key] > 100){
document.getElementById("TopBar").className = "active101";
}
else if(heater[key] > 80){
document.getElementById("TopBar").className = "active81";
}
else if(heater[key] > 60){
document.getElementById("TopBar").className = "active61";
}
else if(heater[key] > 40){
document.getElementById("TopBar").className = "active41";
}
else if(heater[key] > 20){
document.getElementById("TopBar").className = "active21";
}
else {
document.getElementById("TopBar").className = "active0";
}
break;
case "PumpMin":
case "PumpMax":
var OneDecimalPlace = parseFloat(heater[key]).toFixed(1);
var ValKey = key + 'Val'; // eg 'PumpMinVal'
document.getElementById(key).value = OneDecimalPlace;
document.getElementById(key).innerHTML = OneDecimalPlace;
document.getElementById(ValKey).innerHTML = OneDecimalPlace;
break;
case "FanMin":
case "FanMax":
var RPM = heater[key];
var ValKey = key + 'Val'; // eg 'FanMinVal'
document.getElementById(key).value = RPM;
document.getElementById(key).innerHTML = RPM;
document.getElementById(ValKey).innerHTML = RPM;
break;
case "Thermostat":
if(heater[key] != 0) {
document.getElementById("FixedDiv").hidden = true;
document.getElementById("ThermoDiv").hidden = false;
}
else {
document.getElementById("FixedDiv").hidden = false;
document.getElementById("ThermoDiv").hidden = true;
}
break;
}
}
}
}
function setSchedule(){
//clearly need to add some code here to send the Json formatted data to the esp
console.log("Set Schedule Button Press")
}
Date.prototype.toDateInputValue = (function() {
var local = new Date(this);
local.setMinutes(this.getMinutes() - this.getTimezoneOffset());
return local.toJSON().slice(0,10);
});
function sendJSONobject(obj){
var str = JSON.stringify(obj);
console.log("JSON Tx:", str);
Socket.send(str);
}
// Scripts for date handling
Date.prototype.today = function () {
return ((this.getDate() < 10)?"0":"") + this.getDate() +"/"+(((this.getMonth()+1) < 10)?"0":"") + (this.getMonth()+1) +"/"+ this.getFullYear();
}
// Scripts for setting date and time
function setcurrenttime(){
var cmd = {};
cmd.Time = document.getElementById("curtime").value;
sendJSONobject(cmd);
}
function setcurrentdate(){
var cmd = {};
cmd.Date = document.getElementById("curdate").value;
sendJSONobject(cmd);
}
function funcNavLinks() {
var x = document.getElementById("myLinks");
if (x.style.display === "block") {
x.style.display = "none";
} else {
x.style.display = "block";
}
}
function checkTime(i)
{
if (i<10)
{
i="0" + i;
}
return i;
}
function funcdispSettings() {
document.getElementById("Settings").style.display = "block";
currentTime = new Date();
var h = currentTime.getHours();
var m = currentTime.getMinutes();
var s = currentTime.getSeconds();
// add a zero in front of numbers<10
h = checkTime(h);
m = checkTime(m);
s = checkTime(s);
console.log("Hours",h);
console.log("Minutes",m);
console.log("Seconds",s);
document.getElementById("curtime").value = h + ":" + m + ":" + s;
document.getElementById("curdate").value = currentTime.today()
document.getElementById("Home").style.display = "none";
document.getElementById("Advanced").style.display = "none";
document.getElementById("myLinks").style.display ="none";
document.getElementById('curdate').valueAsDate = new Date();
}
function funcdispHome(){
document.getElementById("Settings").style.display = "none";
document.getElementById("Home").style.display = "block";
document.getElementById("Advanced").style.display = "none";
document.getElementById("myLinks").style.display ="none";
}
function funcdispAdvanced(){
document.getElementById("Settings").style.display = "none";
document.getElementById("Home").style.display = "none";
document.getElementById("Advanced").style.display = "block";
document.getElementById("myLinks").style.display ="none";
}
// Function to check the power on/off slide switch.
function OnOffCheck(){
// Get the checkbox status and place in the checkbox variable
var checkBox = document.getElementById("myonoffswitch");
// Send a message to the Devel console of web browser for debugging
console.log("OnOffCheck:", document.getElementById("myonoffswitch").checked);
// If the checkbox is checked, display the output text
// We also need to send a message back into the esp as we cannot directly run Arduino Functions from within the javascript
var cmd = {};
if (checkBox.checked){
//Insert Code Here To Turn On The Heater
console.log("Turning On Heater");
cmd.RunState = 1;
sendJSONobject(cmd);
}
else{
//Insert Code Here To Turn Off The Heater
console.log("Turning Off Heater");
cmd.RunState = 0;
sendJSONobject(cmd);
}
}
function onSlideDone(newVal, JSONKey) {
//elementid must equal the JSON name for each setting
document.getElementById(JSONKey).innerHTML = newVal;
var cmd = {};
cmd[JSONKey] = newVal; // note: variable name needs []
cmd.NVsave = 8861; // named variable DOESN'T !!
sendJSONobject(cmd);
}
function onSlideUpdate(newVal, JSONKey) {
//elementid must equal the JSON name for each setting
document.getElementById(JSONKey).innerHTML = newVal;
}
function SetPumpMin(){
var cmd = {};
cmd['PumpMin'] = document.getElementById("PumpMin").value;
cmd.NVsave = 8861;
sendJSONobject(cmd);
}
</script>
<meta name="viewport" content="height=device-height, width=device-width, initial-scale=1">
<style>
.throb_me {
animation: throbber 1s linear infinite;
}
@keyframes throbber {
50% {
opacity: 0;
}
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
body {
font-family: Arial, Helvetica, sans-serif;
}
.onoffswitch {
position: relative; width: 90px;
-webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
}
.onoffswitch-checkbox {
display: none;
}
.onoffswitch-label {
display: block; overflow: hidden; cursor: pointer;
border: 2px solid #999999; border-radius: 20px;
}
.onoffswitch-inner {
display: block; width: 200%; margin-left: -100%;
transition: margin 0.3s ease-in 0s;
}
.onoffswitch-inner:before, .onoffswitch-inner:after {
display: block; float: left; width: 50%; height: 30px; padding: 0; line-height: 30px;
font-size: 14px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
box-sizing: border-box;
}
.onoffswitch-inner:before {
content: "ON";
padding-left: 10px;
background-color: #34A7C1; color: #FFFFFF;
}
.onoffswitch-inner:after {
content: "OFF";
padding-right: 10px;
background-color: #EEEEEE; color: #999999;
text-align: right;
}
.onoffswitch-switch {
display: block; width: 18px; margin: 6px;
background: #FFFFFF;
position: absolute; top: 0; bottom: 0;
right: 56px;
border: 2px solid #999999; border-radius: 20px;
transition: all 0.3s ease-in 0s;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
margin-left: 0;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
right: 0px;
}
.mobile-container {
margin: auto;
background-color: #555;
height: 500px;
color: white;
border-radius: 10px;
}
.topnav {
overflow: hidden;
background-color: #333;
position: relative;
}
.topnav #myLinks {
display: none;
}
.topnav a {
color: white;
padding: 14px 16px;
text-decoration: none;
font-size: 17px;
display: block;
}
.topnav a.icon {
background: black;
display: block;
position: absolute;
left: 0;
top: 0;
}
.topnav a:hover {
background-color: #ddd;
color: black;
}
.active0 {
background-color: #5e4fa2;
color: black;
}
.active21 {
background-color: #427bb1;
color: #ffffff;
}
.active41 {
background-color: #36c0a3;
color: #ffffff;
}
.active61 {
background-color: #29cf38;
color: #000000;
}
.active81 {
background-color: #92df1b;
color: #ffffff;
}
.active101 {
background-color: #efab0e;
color: #ffffff;
}
.active121 {
background-color: #ff0000;
color: #ffffff;
}
input:checked + .slider {
background-color: #2196F3;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
MainPage {
display: block
}
#Advanced {
display: none
}
#Settings {
display: none
}
}
</style>
<title>Chinese Diesel Heater Web Controller Interface</title>
</head>
<body onload="javascript:init()">
<div class="mobile-container">
<!-- Top Navigation Menu -->
<div class="topnav">
<div id="TopBar" style="padding-left:30px"><a href="javascript:void(0);" onclick="funcdispHome()" >Chinese Diesel Heater Web Control</a></div>
<div id="myLinks">
<a href="javascript:void(0);" onclick="funcdispHome()">Home</a>
<a href="javascript:void(0);" onclick="funcdispSettings()">Settings</a>
<a href="javascript:void(0);" onclick="funcdispAdvanced()">Advanced Settings</a>
</div>
<a href="javascript:void(0);" class="icon" onclick="funcNavLinks()">
</i>=
</a>
</div>
<div style="padding-left:16px">
<span class="MaingPage" id="Home">
<div><H2>Power Control</H2></div>
<div class="onoffswitch" id="onoffswitch">
<input type="checkbox" onclick="OnOffCheck()" name="onoffswitch" class="onoffswitch-checkbox" id="myonoffswitch" clicked>
<label class="onoffswitch-label" for="myonoffswitch">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
</div>
<span class="throb_me" id="RunString" style="visibility:hidden"></span>
<div>
<h2>Temperature Control</h2>
</div>
<input type="range" id="TempDesired" min="8" max="35" step="1" value="22" oninput="onSlideUpdate(this.value, 'TempDesiredVal')" onchange="onSlideDone(this.value, 'TempDesired')">
<div id="ThermoDiv">
<b>Desired Temp: </b> <span id="TempDesiredVal"></span>
</div>
<div id="FixedDiv">
<b>Fixed Hz: </b>
<span id="PumpFixed"></span>
</div>
<div>
<b>Current Temp: </b><span id="TempCurrent">
</div>
<div id="ErrorDiv" style="color:crimson" hidden>
<b>Error <span id="ErrorString"> </b>
</div>
</span>
<div id="Advanced">
<h2><b>Advanced Settings</b></h2>
<br>
<h3><b>Minimum Fuel Settings</b></h3>
<div>
<b>Pump Min: </b><span id="PumpMinVal"> </span>
<input type="range" id="PumpMin" min="1" max="10" step=".1" oninput="onSlideUpdate(parseFloat(this.value).toFixed(1), 'PumpMinVal')" onchange="onSlideDone(this.value, 'PumpMin')">
</div>
<div>
<b>Fan Min: </b><span id="FanMinVal"> </span>
<input type="range" id="FanMin" min="1000" max="5000" step="10" oninput="onSlideUpdate(this.value, 'FanMinVal')" onchange="onSlideDone(this.value, 'FanMin')">
</div>
<br>
<h3><b>Maximum Fuel Settings</b></h3>
<div>
<b>Pump Max: </b><span id="PumpMaxVal"> </span>
<input type="range" id="PumpMax" min=".5" max="10" step=".1" oninput="onSlideUpdate(parseFloat(this.value).toFixed(1), 'PumpMaxVal')" onchange="onSlideDone(this.value, 'PumpMax')">
</div>
<div>
<b>Fan Max: </b><span id="FanMaxVal"> </span>
<input type="range" id="FanMax" min="1000" max="5000" step="10" oninput="onSlideUpdate(this.value, 'FanMaxVal')" onchange="onSlideDone(this.value, 'FanMax')">
</div>
</div>
<Div id="Settings">
Current Date:<br>
<input type="date" id="curdate"><input type="button" Value="Set Date" onclick="setcurrentdate()">
<br>
Current Time (24 Hour Format):<br>
<input type="time" id="curtime"> <input type="button" Value="Set Time" onclick="setcurrenttime()">
<hr></hr>
<br><br>
Timer1: <input type="checkbox" border-radius="4px" name="Timer" id="Timer1onoff"> <input type="text" class="schedule" id="Timer1Start"> <input type="text" id="Timer1End"> <br>
Timer2: <input type="checkbox" border-radius="4px" name="Tue"> <input type="text" class="schedule" id="Timer2Start"> <input type="text" id="Timer2End"><br>
<input type="button" Value="Save Schedule" onclick="setSchedule()">
</Div>
</body>
</html>

View file

@ -1,102 +0,0 @@
1249177ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74
+21ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
Bluetooth data not sent, CRC error
1250198ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74
+23ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
Bluetooth data not sent, CRC error
*** SWITCHED INTO VERBOSE MODE ****
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
1251221ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74 :6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6
dT{16}:6,RD(8B)
dT{1}:6,RD(1D)
dT{1}:6,RD(76) <<<<<<<<<<<<<<<<<<<<<<<<<< THIS SHOULD BE FIRST RX BYTE!!!!
dT{1}:6,RD(16)
dT{1}:6,RD(0)
dT{2}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(84)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(84)
dT{2}:6,RD(0)
dT{1}:6,RD(2F)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{2}:6,RD(0)
dT{1}:6,RD(8)
dT{1}:6,RD(0)
dT{1}:6,RD(1A)
dT{1}:6,RD(64)
dT{1}:6,RD(0)
:7 +48ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
Bluetooth data not sent, CRC error
:8
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
8< (lots of state :0 snipped)
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
:5:5:5:5:5:5:5:5:5:5
1252268ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74
:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6
dT{16}:6,RD(8B)
dT{1}:6,RD(1D)
dT{1}:6,RD(76) <<<<<<<<<<<<<<<<<<<<<<<<<< THIS SHOULD BE FIRST RX BYTE!!!!
dT{2}:6,RD(16)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(84)
dT{1}:6,RD(0)
dT{2}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(84)
dT{1}:6,RD(0)
dT{1}:6,RD(2F)
dT{1}:6,RD(0)
dT{2}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(8)
dT{1}:6,RD(0)
dT{1}:6,RD(1A)
dT{2}:6,RD(64)
dT{1}:6,RD(0):7
+49ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
Bluetooth data not sent, CRC error
:8
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0

View file

@ -1,117 +0,0 @@
Start updating sketch
Progress: 100%
End
*WM: [1] AutoConnect
*WM: [2] ESP32 event handler enabled
*WM: [2] Connecting as wifi client...
*WM: [2] setSTAConfig static ip not set
*WM: [3] WIFI station disconnect
*WM: [1] Connecting to saved AP: WigginsCorner
*WM: [3] WiFi station enable
*WM: [1] connectTimeout not set, ESP waitForConnectResult...
*WM: [2] [EVENT] 4
*WM: [2] [EVENT] 7
*WM: [2] Connection result: WL_CONNECTED
*WM: [3] lastconxresult: WL_CONNECTED
*WM: [1] AutoConnect: SUCCESS
*WM: [1] STA IP Address: 192.168.0.101
connected...yeey :)
Ready
IP address: 192.168.0.101
Attempting to detect HC-05 Bluetooth module...
@ 9600 baud... OK.
HC-05 found
Setting Name to "Diesel Heater"... OK
Setting baud rate to 9600N81...OK
2313ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +22ms [HTR] 76 16 00 08 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 0B DE
3335ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +22ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
4357ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
5380ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
6404ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
7427ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
8451ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
9474ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
10498ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
11521ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
12545ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
13568ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
14592ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
15615ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
16639ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
17662ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
18686ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
19709ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
20732ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
21756ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
22780ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
23803ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
24827ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
25850ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
26873ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
27897ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
28920ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 07 6C 2F 66 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
29944ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
30967ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
31991ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
33014ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
34038ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
35061ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
36084ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
37108ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
38131ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
39155ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
40178ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
41202ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
42225ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
43249ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
44272ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
45296ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
46319ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
47342ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
48366ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
49390ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
50413ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
51436ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
52460ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
53484ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
54507ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
55531ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
56555ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
57578ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
58602ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
59625ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
60649ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +22ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
61671ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
62695ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
63718ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
64742ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
65765ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
66788ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
67812ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
68836ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
69859ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
70882ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
71906ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
72929ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
73952ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
74976ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
76000ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
77023ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 Timeout collecting BTC heater response data, returning to Idle State
78047ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
Bluetooth data not sent, CRC error
79070ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
Bluetooth data not sent, CRC error
80093ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
+24ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
Bluetooth data not sent, CRC error
81117ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
Bluetooth data not sent, CRC error
82140ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A

View file

@ -1,46 +0,0 @@
1174404ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
1175426ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1176448ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+23ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1177471ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
1178493ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+21ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
1179515ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1180537ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
1181559ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+23ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1182583ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30 Timeout collecting BTC heater response data, returning to Idle State
1183588ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1184611ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+21ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
1185632ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1186654ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30 Timeout collecting BTC heater response data, returning to Idle State
1187676ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:58A8 data:8B
Bluetooth data not sent, CRC error
1188699ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 1D 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A verifyCRC FAILED: calc:B94 data:9A
Bluetooth data not sent, CRC error
1189721ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 4E 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A verifyCRC FAILED: calc:27B2 data:9A
Bluetooth data not sent, CRC error
1190743ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 4E 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:748E data:8B
Bluetooth data not sent, CRC error
1191765ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:58A8 data:8B
Bluetooth data not sent, CRC error
1192788ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+21ms [HTR] 1D 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A verifyCRC FAILED: calc:B94 data:9A
Bluetooth data not sent, CRC error
1193810ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+23ms [HTR] 4E 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:748E data:8B
Bluetooth data not sent, CRC error
1194833ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30 Timeout collecting BTC heater response data, returning to Idle State

View file

@ -1,786 +0,0 @@
[Starting] Opening the serial port - COM9
oad:0x3fff0018,len:4
l<EFBFBD><EFBFBD><EFBFBD><EFBFBD>fff001c,len:952
load:0x40078000,len:6084
load:0x40080000,len:7936
entry 0x40080310
[Info] Opened the serial port - COM9
1046[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
1086[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
2070[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
2110[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
No Bluetooth client
Free heap 96224
3093[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
3133[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
4113[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
4153[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
5132[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
5172[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
6155[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
6195[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
7179[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
7219[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 10 00 00 00 00 00 08 00 1B 64 00 A3 A2
No Bluetooth client
Free heap 96224
8202[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
8242[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
No Bluetooth client
Free heap 96224
9222[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
9262[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 11 00 00 00 00 00 08 00 1B 64 00 5F A6
No Bluetooth client
Free heap 96224
10245[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
10285[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 11 00 00 00 00 00 08 00 1B 64 00 5F A6
No Bluetooth client
Free heap 96224
11265[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
11305[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
12289[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
12329[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
13308[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
13348[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
14331[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
14371[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
15354[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
15394[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
16378[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
16418[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
17401[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
17441[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
18425[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
18465[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
19445[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
19485[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
20468[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
20508[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
21488[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
21528[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
No Bluetooth client
Free heap 96224
22508[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
22558[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
Free heap 92384
[CMD]degC19
Command decode: degC = 19
[CMD]save
Command decode: NV save
[CMD]degC19
Command decode: degC = 19
[CMD]save
Command decode: NV save
23531[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
23581[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
Free heap 92384
[CMD]degC19
Command decode: degC = 19
[CMD]save
Command decode: NV save
24550[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
24600[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
Free heap 92384
25573[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
25623[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
Free heap 92384
26598[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
26648[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
Free heap 92384
27620[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
27670[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 10 00 00 00 00 00 08 00 1B 64 00 A3 A2
Free heap 92384
28643[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
28693[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
Free heap 92384
29667[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
29717[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
Free heap 92384
[CMD]ON
Command decode: Heater ON
30691[BTC] 76 16 A0 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC E1 57
30741[HTR] 76 16 01 00 00 8B 00 00 00 53 00 11 00 00 00 00 00 00 00 1B 64 00 96 5A
Free heap 92384
31712[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
31762[HTR] 76 16 02 01 00 8A 00 00 00 0A 00 10 00 02 00 5F 00 00 00 1B 64 00 C9 1D
Free heap 92384
32733[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
32783[HTR] 76 16 02 01 00 89 00 00 00 0B 00 10 00 04 00 B7 00 00 00 1B 64 00 16 AC
Free heap 92384
33753[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
33803[HTR] 76 16 02 01 00 89 00 00 00 0E 00 10 00 07 01 0E 00 00 00 1B 64 00 E4 5D
Free heap 92384
34777[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
34827[HTR] 76 16 02 01 00 89 00 00 00 11 00 10 00 09 01 62 00 00 00 1B 64 00 1D 97
Free heap 92384
35800[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
35850[HTR] 76 16 02 01 00 89 00 50 00 14 00 10 00 0A 01 86 00 00 00 1B 64 00 DA 7B
Free heap 92384
36822[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
36872[HTR] 76 16 02 01 00 89 00 C8 00 17 00 10 00 0B 01 C5 00 00 00 1B 64 00 27 99
Free heap 92384
37845[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
37895[HTR] 76 16 02 01 00 89 01 C2 00 1A 00 10 00 0E 02 21 00 00 00 1B 64 00 B6 1A
Free heap 92384
38867[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
38917[HTR] 76 16 02 01 00 89 02 80 00 1C 00 10 00 0F 02 41 00 00 00 1B 64 00 26 FC
Free heap 92384
39889[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
39939[HTR] 76 16 02 01 00 88 03 D4 00 1D 00 10 00 12 02 80 00 00 00 1B 64 00 04 7F
Free heap 92384
40912[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
40962[HTR] 76 16 02 01 00 88 04 CE 00 20 00 10 00 14 02 C0 00 00 00 1B 64 00 E4 9F
Free heap 92384
41935[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
41985[HTR] 76 16 02 01 00 88 06 04 00 20 00 10 00 16 02 EC 00 00 00 1B 64 00 70 A0
Free heap 92384
42958[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
43008[HTR] 76 16 02 01 00 88 06 9A 00 20 00 10 00 17 02 F8 00 00 00 1B 64 00 89 E7
Free heap 92384
43981[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
44031[HTR] 76 16 02 01 00 88 07 3A 00 20 00 10 00 1A 03 23 00 00 00 1B 64 00 30 74
Free heap 92384
45005[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
45055[HTR] 76 16 02 01 00 88 07 80 00 20 00 10 00 1C 03 43 00 00 00 1B 64 00 E5 05
Free heap 92384
46029[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
46079[HTR] 76 16 02 01 00 88 07 B2 00 1E 00 10 00 1E 03 5F 00 00 00 1B 64 00 2F 24
Free heap 92384
47052[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
47102[HTR] 76 16 02 01 00 87 07 B2 00 1A 00 10 00 1F 03 5F 00 00 00 1B 64 00 C8 12
Free heap 92384
48076[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
48126[HTR] 76 16 02 01 00 87 07 80 00 19 00 10 00 21 03 77 00 00 00 1B 64 00 7D 15
Free heap 92384
49100[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
49150[HTR] 76 16 02 01 00 87 07 26 00 18 00 10 00 23 03 8F 00 00 00 1B 64 00 29 51
Free heap 92384
50120[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
50170[HTR] 76 16 02 01 00 87 06 E0 00 18 00 10 00 25 03 9F 00 00 00 1B 64 00 8A EC
Free heap 92384
51144[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
51194[HTR] 76 16 02 01 00 87 06 7C 00 18 00 10 00 28 03 B3 00 00 00 1B 64 00 B1 C5
Free heap 92384
52163[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
52213[HTR] 76 16 02 01 00 87 06 36 00 18 00 10 00 2A 03 C7 00 00 00 1B 64 00 E1 22
Free heap 92384
53185[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
53235[HTR] 76 16 02 01 00 87 05 E6 00 19 00 10 00 2C 03 CF 00 00 00 1B 64 00 AD 12
Free heap 92384
54207[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
54257[HTR] 76 16 02 01 00 87 05 C8 00 18 00 10 00 2D 03 C3 00 00 00 1B 64 00 A0 7F
Free heap 92384
55229[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
55279[HTR] 76 16 02 01 00 87 05 A0 00 19 00 10 00 2F 03 CF 00 00 00 1B 64 00 6F C0
Free heap 92384
56249[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
56299[HTR] 76 16 02 01 00 86 05 8C 00 18 00 10 00 32 03 D3 00 00 00 1B 64 00 F2 F7
Free heap 92384
57272[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
57322[HTR] 76 16 02 01 00 86 05 8C 00 18 00 10 00 33 03 DF 00 00 00 1B 64 00 62 36
Free heap 92384
58292[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
58342[HTR] 76 16 02 01 00 86 05 8C 00 18 00 10 00 35 03 D3 00 00 00 1B 64 00 C2 D1
Free heap 92384
59315[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
59365[HTR] 76 16 02 01 00 86 05 8C 00 19 00 10 00 37 03 DF 00 00 00 1B 64 00 23 06
Free heap 92384
60335[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
60385[HTR] 76 16 02 01 00 86 05 8C 00 19 00 10 00 39 03 DB 00 00 00 1B 64 00 83 0F
Free heap 92384
61355[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
61405[HTR] 76 16 02 01 00 85 05 8C 00 18 00 10 00 3B 03 E6 00 00 00 1B 64 00 51 08
Free heap 92384
62379[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
62429[HTR] 76 16 02 01 00 85 05 96 00 19 00 10 00 3D 03 DF 00 00 00 1B 64 00 78 12
Free heap 92384
63398[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
63448[HTR] 76 16 02 01 00 85 05 8C 00 19 00 10 00 3F 03 DF 00 00 00 1B 64 00 13 91
Free heap 92384
64418[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
64468[HTR] 76 16 02 01 00 85 05 96 00 19 00 10 00 41 03 E6 00 00 00 1B 64 00 B9 8B
Free heap 92384
65441[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
65491[HTR] 76 16 02 01 00 85 05 8C 00 1A 00 10 00 42 03 DF 00 00 00 1B 64 00 82 A9
Free heap 92384
66462[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
66512[HTR] 76 16 02 01 00 85 05 96 00 1A 00 10 00 44 03 E6 00 00 00 1B 64 00 2A B1
Free heap 92384
67485[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
67535[HTR] 76 16 02 01 00 84 05 96 00 19 00 11 00 47 03 EA 00 00 00 1B 64 00 75 39
Free heap 92384
68508[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
68558[HTR] 76 16 02 01 00 84 05 A0 00 1A 00 10 00 49 03 F6 00 00 00 1B 64 00 FD 1F
Free heap 92384
69530[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
69580[HTR] 76 16 02 01 00 84 05 AA 00 1A 00 11 00 4A 03 EE 00 00 00 1B 64 00 F7 1D
Free heap 92384
70552[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
70602[HTR] 76 16 02 01 00 84 05 AA 00 1A 00 10 00 4C 03 F2 00 00 00 1B 64 00 6A EF
Free heap 92384
71574[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
71624[HTR] 76 16 02 01 00 83 05 B4 00 19 00 11 00 4F 03 FA 00 00 00 1B 64 00 5C 5F
Free heap 92384
72597[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
72647[HTR] 76 16 02 01 00 83 05 B4 00 1A 00 10 00 51 04 06 00 00 00 1B 64 00 2A A2
Free heap 92384
73621[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
73671[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 10 00 52 03 FE 00 00 00 1B 64 00 F4 04
Free heap 92384
74644[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
74694[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 10 00 54 04 06 00 00 00 1B 64 00 7D 17
Free heap 92384
75667[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
75717[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 11 00 56 04 06 00 00 00 1B 64 00 60 08
Free heap 92384
76690[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
76740[HTR] 76 16 02 01 00 82 05 BE 00 1A 00 10 00 58 04 12 00 00 00 1B 64 00 EC 47
Free heap 92384
77712[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
77762[HTR] 76 16 02 01 00 82 05 C8 00 1A 00 10 00 58 04 06 00 00 00 1B 64 00 CB E5
Free heap 92384
78735[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
78785[HTR] 76 16 02 01 00 82 05 C8 00 1A 00 10 00 58 03 FA 00 00 00 1B 64 00 22 98
Free heap 92384
79756[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
79806[HTR] 76 16 02 01 00 82 05 D2 00 1A 00 10 00 59 03 F6 00 00 00 1B 64 00 B9 C3
Free heap 92384
80779[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
80829[HTR] 76 16 02 01 00 82 05 D2 00 1A 00 10 00 59 03 EE 00 00 00 1B 64 00 B8 5B
Free heap 92384
81803[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
81853[HTR] 76 16 02 01 00 83 05 D2 00 1C 00 10 00 59 03 E6 00 00 00 1B 64 00 2E 8A
Free heap 92384
82822[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
82872[HTR] 76 16 02 01 00 82 05 DC 00 1A 00 11 00 59 03 DF 00 00 00 1B 64 00 83 F1
Free heap 92384
83845[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
83895[HTR] 76 16 02 01 00 82 05 DC 00 1A 00 10 00 59 03 DB 00 00 00 1B 64 00 BF B0
Free heap 92384
84867[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
84917[HTR] 76 16 02 01 00 83 05 DC 00 1A 00 10 00 59 03 D3 00 00 00 1B 64 00 EF 68
Free heap 92384
85888[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
85938[HTR] 76 16 02 01 00 83 05 DC 00 1B 00 11 00 59 03 D7 00 00 00 1B 64 00 52 2B
Free heap 92384
86910[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
86960[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 10 00 59 03 CF 00 00 00 1B 64 00 BC 0D
Free heap 92384
87933[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
87983[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 10 00 59 03 CF 00 00 00 1B 64 00 BC 0D
Free heap 92384
88956[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
89006[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 11 00 59 03 CB 00 00 00 1B 64 00 80 4C
Free heap 92384
89979[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
90029[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 10 00 59 03 C7 00 00 00 1B 64 00 7C 84
Free heap 92384
91002[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
91052[HTR] 76 16 02 01 00 83 05 E6 00 1A 00 11 00 59 03 C3 00 00 00 1B 64 00 C1 C7
Free heap 92384
92024[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
92074[HTR] 76 16 02 01 00 83 05 E6 00 1A 00 11 00 59 03 C3 00 00 00 1B 64 00 C1 C7
Free heap 92384
93047[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
93097[HTR] 76 16 02 01 00 83 05 DC 00 1A 00 11 00 59 03 BF 00 00 00 1B 64 00 15 C0
Free heap 92384
94070[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
94120[HTR] 76 16 02 01 00 83 05 DC 00 1D 00 11 00 59 03 BF 00 00 00 1B 64 00 52 CB
Free heap 92384
95094[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
95144[HTR] 76 16 02 01 00 83 05 D2 00 1A 00 10 00 59 03 BF 00 00 00 1B 64 00 ED 4A
Free heap 92384
96117[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
96167[HTR] 76 16 02 01 00 83 05 D2 00 1A 00 11 00 59 03 BF 00 00 00 1B 64 00 11 4E
Free heap 92384
97139[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
97189[HTR] 76 16 02 01 00 83 05 D2 00 1A 00 10 00 59 03 BF 00 00 00 1B 64 00 ED 4A
Free heap 92384
98162[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
98212[HTR] 76 16 02 01 00 83 05 C8 00 1A 00 11 00 59 03 BB 00 00 00 1B 64 00 DA 91
Free heap 92384
99185[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
99235[HTR] 76 16 02 01 00 83 05 C8 00 1B 00 11 00 59 03 B7 00 00 00 1B 64 00 5B 5F
Free heap 92384
100207[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
100257[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 11 00 59 03 B7 00 00 00 1B 64 00 FC AB
Free heap 92384
101230[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
101280[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 10 00 59 03 BB 00 00 00 1B 64 00 00 63
Free heap 92384
102252[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
102302[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 10 00 59 03 B7 00 00 00 1B 64 00 81 AD
Free heap 92384
103276[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
103326[HTR] 76 16 02 01 00 83 05 B4 00 1A 00 10 00 59 03 B7 00 00 00 1B 64 00 07 25
Free heap 92384
104298[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
104348[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 10 00 59 03 B3 00 00 00 1B 64 00 41 E8
Free heap 92384
105320[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
105370[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 BD EC
Free heap 92384
106344[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
106394[HTR] 76 16 02 01 00 83 05 D2 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 90 80
Free heap 92384
107366[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
107416[HTR] 76 16 02 01 00 83 05 DC 00 1B 00 10 00 59 03 B3 00 00 00 1B 64 00 68 0A
Free heap 92384
108388[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
108438[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 87 B4
Free heap 92384
109411[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
109461[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 89 22
Free heap 92384
110435[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
110485[HTR] 76 16 02 01 00 83 05 FA 00 1B 00 11 00 59 03 AF 00 00 00 1B 64 00 4F 75
Free heap 92384
111457[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
111507[HTR] 76 16 02 01 00 83 05 FA 00 1B 00 11 00 59 03 AF 00 00 00 1B 64 00 4F 75
Free heap 92384
112480[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
112530[HTR] 76 16 02 01 00 83 05 FA 00 1A 00 11 00 59 03 AF 00 00 00 1B 64 00 CE 77
Free heap 92384
113500[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
113550[HTR] 76 16 02 01 00 83 05 FA 00 1A 00 11 00 59 03 AF 10 00 00 1B 64 00 5E 75
Free heap 92384
114523[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
114573[HTR] 76 16 02 01 00 81 05 F0 00 1A 00 11 00 59 03 AF 10 00 00 1B 64 00 39 5E
Free heap 92384
115546[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
115596[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 B3 10 00 00 1B 64 00 19 20
Free heap 92384
116569[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
116619[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 AF 10 00 00 1B 64 00 D8 FD
Free heap 92384
117593[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
117643[HTR] 76 16 02 01 00 82 05 FA 00 1A 00 11 00 59 03 AF 10 00 00 1B 64 00 CE 24
Free heap 92384
118616[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
118666[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 AB 10 00 00 1B 64 00 18 B8
Free heap 92384
119639[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
119689[HTR] 76 16 02 01 00 83 05 FA 00 1B 00 11 00 59 03 AB 10 00 00 1B 64 00 1F 32
Free heap 92384
120661[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
120711[HTR] 76 16 02 01 00 80 06 04 00 1A 00 11 00 59 03 AB 10 00 00 1B 64 00 DF FE
Free heap 92384
121685[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
121735[HTR] 76 16 02 01 00 83 06 18 00 1C 00 11 00 59 03 AF 10 00 00 1B 64 00 20 5E
Free heap 92384
122708[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
122758[HTR] 76 16 02 01 00 83 06 22 00 1C 00 11 00 59 03 A7 10 00 00 1B 64 00 F3 6D
Free heap 92384
123728[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
123778[HTR] 76 16 02 01 00 83 06 2C 00 1C 00 11 00 59 03 AB 10 00 00 1B 64 00 F7 2F
Free heap 92384
124748[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
124798[HTR] 76 16 02 01 00 83 06 40 00 1C 00 11 00 59 03 AB 11 00 00 1B 64 00 0B 42
Free heap 92384
125770[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
125820[HTR] 76 16 02 01 00 83 06 54 00 1C 00 11 00 59 03 AB 11 00 00 1B 64 00 04 56
Free heap 92384
126792[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
126842[HTR] 76 16 02 01 00 83 06 5E 00 1C 00 11 00 59 03 AF 11 00 00 1B 64 00 C3 99
Free heap 92384
127812[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
127862[HTR] 76 16 02 01 00 83 06 68 00 1C 00 11 00 59 03 AB 11 00 00 1B 64 00 15 6A
Free heap 92384
128833[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
128883[HTR] 76 16 02 01 00 83 06 7C 00 1D 00 11 00 59 03 AB 11 00 00 1B 64 00 9B 7C
Free heap 92384
129853[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
129903[HTR] 76 16 02 01 00 83 06 7C 00 1D 00 11 00 59 03 AB 11 00 00 1B 64 00 9B 7C
Free heap 92384
130874[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
130924[HTR] 76 16 02 01 00 83 06 86 00 1D 00 11 00 59 03 AB 11 00 00 1B 64 00 D8 06
Free heap 92384
131894[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
131944[HTR] 76 16 02 01 00 83 06 90 00 1D 00 11 00 59 03 AF 11 00 00 1B 64 00 16 D5
Free heap 92384
132915[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
132965[HTR] 76 16 02 01 00 83 06 9A 00 1E 00 11 00 59 03 AB 11 00 00 1B 64 00 12 1F
Free heap 92384
133938[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
133988[HTR] 76 16 02 01 00 83 06 A4 00 1E 00 11 00 59 03 AF 12 00 00 1B 64 00 F1 E4
Free heap 92384
134957[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
135007[HTR] 76 16 02 01 00 83 06 AE 00 21 00 11 00 59 03 AB 12 00 00 1B 64 00 C9 7E
Free heap 92384
135981[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
136031[HTR] 76 16 02 01 00 83 06 C2 00 1F 00 11 00 59 03 AB 12 00 00 1B 64 00 9A 45
Free heap 92384
137003[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
137053[HTR] 76 16 02 01 00 82 06 CC 00 1E 00 11 00 59 03 A7 12 00 00 1B 64 00 8F 54
Free heap 92384
ASSERT_PARAM(512 0), in rwbt.c at line 273
Guru Meditation Error: Core 0 panic'ed (Interrupt wdt timeout on CPU0)
Core 0 register dump:
PC : 0x400850c8 PS : 0x00060034 A0 : 0x80088b40 A1 : 0x3ffc05b0
A2 : 0x00000001 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x60008054
A6 : 0x3ffc1030 A7 : 0x60008050 A8 : 0x800850c5 A9 : 0x3ffc0590
A10 : 0x00000004 A11 : 0x00000000 A12 : 0x6000804c A13 : 0xffffffff
A14 : 0x00000000 A15 : 0xfffffffc SAR : 0x00000004 EXCCAUSE: 0x00000005
EXCVADDR: 0x00000000 LBEG : 0x40084ffd LEND : 0x40085004 LCOUNT : 0x00000000
Core 0 was running in ISR context:
EPC1 : 0x4017d35e EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x400850c8
Backtrace: 0x400850c8:0x3ffc05b0 0x40088b3d:0x3ffc05d0 0x400891cf:0x3ffc05f0 0x400817ad:0x3ffc0610 0x4017d35b:0x00000000
Core 1 register dump:
PC : 0x400d1faa PS : 0x00060334 A0 : 0x800d1258 A1 : 0x3ffd55d0
A2 : 0x00000000 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x00000000
A6 : 0x00000000 A7 : 0x3ffd36c0 A8 : 0x3ffc4920 A9 : 0x3ffd55b0
A10 : 0x3ffe7f84 A11 : 0x3ffd0814 A12 : 0xd4000000 A13 : 0x3ffd54d0
A14 : 0x00000002 A15 : 0x3ffd36c0 SAR : 0x0000000a EXCCAUSE: 0x00000005
EXCVADDR: 0x00000000 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0x00000000
Backtrace: 0x400d1faa:0x3ffd55d0 0x400d1255:0x3ffd55f0 0x400d1718:0x3ffd5610 0x401692c4:0x3ffd5630
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:952
load:0x40078000,len:6084
load:0x40080000,len:7936
entry 0x40080310
1045[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
1085[HTR] 76 16 02 01 00 81 06 FE 00 1F 00 11 00 59 03 A7 12 00 00 1B 64 00 EB 14
No Bluetooth client
Free heap 96196
2065[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
2105[HTR] 76 16 02 01 00 82 07 26 00 20 00 11 00 59 03 AB 12 00 00 1B 64 00 2E 64
No Bluetooth client
Free heap 96196
3086[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
3126[HTR] 76 16 02 01 00 83 07 3A 00 21 00 11 00 59 03 A7 12 00 00 1B 64 00 36 E7
No Bluetooth client
Free heap 96196
4107[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
4147[HTR] 76 16 02 01 00 82 07 62 00 21 00 11 00 59 03 AF 12 00 00 1B 64 00 5C 67
No Bluetooth client
Free heap 96196
5126[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
5166[HTR] 76 16 02 01 00 82 07 6C 00 20 00 11 00 59 03 AF 13 00 00 1B 64 00 08 EA
No Bluetooth client
Free heap 96196
6146[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
6186[HTR] 76 16 02 01 00 82 07 94 00 22 00 11 00 59 03 AB 13 00 00 1B 64 00 C8 50
No Bluetooth client
Free heap 96196
7167[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
7207[HTR] 76 16 02 01 00 82 07 A8 00 22 00 11 00 59 03 AF 13 00 00 1B 64 00 19 29
No Bluetooth client
Free heap 96196
8187[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
8227[HTR] 76 16 02 01 00 82 07 BC 00 21 00 11 00 59 03 AB 13 00 00 1B 64 00 15 7D
No Bluetooth client
Free heap 96196
9208[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
9248[HTR] 76 16 02 01 00 82 07 C6 00 23 00 11 00 59 03 AB 13 00 00 1B 64 00 74 80
No Bluetooth client
Free heap 96196
10233[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
10273[HTR] 76 16 02 01 00 82 07 E4 00 23 00 11 00 59 03 AF 13 00 00 1B 64 00 AD 67
No Bluetooth client
Free heap 96196
11253[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
11293[HTR] 76 16 02 01 00 82 07 F8 00 24 00 11 00 58 03 AF 13 00 00 1B 64 00 73 7D
No Bluetooth client
Free heap 96196
12274[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
12314[HTR] 76 16 02 01 00 82 08 0C 00 24 00 11 00 59 03 AF 13 00 00 1B 64 00 50 C1
No Bluetooth client
Free heap 96196
13294[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
13334[HTR] 76 16 02 01 00 82 08 20 00 24 00 11 00 59 03 AF 14 00 00 1B 64 00 FA EC
No Bluetooth client
Free heap 96196
14314[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
14354[HTR] 76 16 02 01 00 82 08 48 00 25 00 11 00 59 03 AF 14 00 00 1B 64 00 55 86
No Bluetooth client
Free heap 96196
15338[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
15378[HTR] 76 16 02 01 00 82 08 66 00 25 00 11 00 59 03 B3 14 00 00 1B 64 00 88 F5
No Bluetooth client
Free heap 96196
16362[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
16402[HTR] 76 16 02 01 00 82 08 84 00 26 00 11 00 59 03 B3 14 00 00 1B 64 00 02 92
No Bluetooth client
Free heap 96196
17382[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
17422[HTR] 76 16 02 01 00 82 08 A2 00 26 00 11 00 59 03 AF 14 00 00 1B 64 00 D9 E9
No Bluetooth client
Free heap 96196
18403[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
18443[HTR] 76 16 02 01 00 80 08 C0 00 27 00 11 00 59 03 B3 14 00 00 1B 64 00 D0 75
No Bluetooth client
Free heap 96196
19423[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
19463[HTR] 76 16 02 01 00 82 08 D4 00 27 00 11 00 59 03 B3 14 00 00 1B 64 00 BF C0
No Bluetooth client
Free heap 96196
20443[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
20483[HTR] 76 16 02 01 00 82 08 E8 00 27 00 12 00 5A 03 AF 15 00 00 1B 64 00 0A 3B
No Bluetooth client
Free heap 96196
21464[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
21504[HTR] 76 16 02 01 00 82 08 FC 00 28 00 11 00 59 03 B3 15 00 00 1B 64 00 7F FD
No Bluetooth client
Free heap 96196
22488[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
22528[HTR] 76 16 02 01 00 82 09 10 00 27 00 12 00 59 03 AF 15 00 00 1B 64 00 28 16
No Bluetooth client
Free heap 96196
23508[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
23548[HTR] 76 16 02 01 00 82 09 2E 00 28 00 12 00 59 03 B3 15 00 00 1B 64 00 F6 61
No Bluetooth client
Free heap 96196
24529[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
24569[HTR] 76 16 02 01 00 80 09 42 00 28 00 11 00 59 03 B3 15 00 00 1B 64 00 FF A3
No Bluetooth client
Free heap 96196
25549[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
25589[HTR] 76 16 02 01 00 82 09 60 00 2A 00 12 00 59 03 AF 15 00 00 1B 64 00 41 75
No Bluetooth client
Free heap 96196
26570[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
26610[HTR] 76 16 02 01 00 82 09 74 00 2A 00 12 00 59 03 B3 16 00 00 1B 64 00 BC BC
No Bluetooth client
Free heap 96196
27591[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
27631[HTR] 76 16 02 01 00 82 09 9C 00 2A 00 12 00 59 03 B7 16 00 00 1B 64 00 32 11
No Bluetooth client
Free heap 96196
28613[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
28653[HTR] 76 16 02 01 00 82 09 B0 00 2B 00 12 00 59 03 B7 16 00 00 1B 64 00 AE 3F
No Bluetooth client
Free heap 96196
29633[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
29673[HTR] 76 16 02 01 00 82 09 CE 00 2B 00 12 00 59 03 B7 16 00 00 1B 64 00 8E C1
No Bluetooth client
Free heap 96196
30653[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
30693[HTR] 76 16 02 01 00 82 09 EC 00 2B 00 12 00 59 03 B7 16 00 00 1B 64 00 97 63
No Bluetooth client
Free heap 96196
31674[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
31714[HTR] 76 16 02 01 00 82 09 F6 00 2C 00 12 00 59 03 B7 16 00 00 1B 64 00 DB F2
No Bluetooth client
Free heap 96196
32694[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
32734[HTR] 76 16 02 01 00 82 0A 14 00 2C 00 12 00 59 03 B7 17 00 00 1B 64 00 B2 D1
No Bluetooth client
Free heap 96196
33718[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
33758[HTR] 76 16 02 01 00 82 0A 1E 00 2D 00 12 00 59 03 B7 17 00 00 1B 64 00 34 59
No Bluetooth client
Free heap 96196
34740[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
34780[HTR] 76 16 02 01 00 82 0A 32 00 2D 00 12 00 58 03 B7 17 00 00 1B 64 00 B9 78
No Bluetooth client
Free heap 96196
35760[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
35800[HTR] 76 16 02 01 00 82 0A 46 00 2E 00 12 00 59 03 B7 17 00 00 1B 64 00 CD 04
No Bluetooth client
Free heap 96196
36782[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
36822[HTR] 76 16 02 01 00 82 0A 5A 00 2E 00 12 00 59 03 B7 17 00 00 1B 64 00 C4 18
No Bluetooth client
Free heap 96196
37803[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
37843[HTR] 76 16 02 01 00 82 0A 78 00 2F 00 12 00 59 03 B7 17 00 00 1B 64 00 5C B8
No Bluetooth client
Free heap 96196
38823[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
38863[HTR] 76 16 02 01 00 82 0A 8C 00 2F 00 12 00 59 03 B7 18 00 00 1B 64 00 E4 4C
No Bluetooth client
Free heap 96196
39843[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
39883[HTR] 76 16 02 01 00 80 0A AA 00 2F 00 12 00 59 03 B3 18 00 00 1B 64 00 5E 0E
No Bluetooth client
Free heap 96196
40864[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
40904[HTR] 76 16 02 01 00 82 0A D2 00 30 00 12 00 59 03 BB 18 00 00 1B 64 00 43 74
No Bluetooth client
Free heap 96196
41884[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
41924[HTR] 76 16 02 01 00 80 0A E6 00 30 00 12 00 59 03 B7 18 00 00 1B 64 00 34 2D
No Bluetooth client
Free heap 96196
42906[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
42946[HTR] 76 16 02 01 00 82 0B 0E 00 31 00 12 00 59 03 B7 18 00 00 1B 64 00 0B A7
No Bluetooth client
Free heap 96196
43925[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
43965[HTR] 76 16 02 01 00 80 0B 36 00 31 00 12 00 59 03 B7 19 00 00 1B 64 00 A8 3F
No Bluetooth client
Free heap 96196
44946[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
44986[HTR] 76 16 02 01 00 82 0B 54 00 32 00 12 00 59 03 BB 19 00 00 1B 64 00 22 B5
No Bluetooth client
Free heap 96196
45965[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
46005[HTR] 76 16 02 01 00 82 0B 68 00 32 00 13 00 59 03 B7 19 00 00 1B 64 00 CF 41
No Bluetooth client
Free heap 96196
46986[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
47026[HTR] 76 16 02 01 00 82 0B 7C 00 33 00 12 00 59 03 BB 19 00 00 1B 64 00 BD 9F
No Bluetooth client
Free heap 96196
48008[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
48048[HTR] 76 16 02 01 00 82 0B 9A 00 32 00 12 00 59 03 BB 1A 00 00 1B 64 00 45 FB
No Bluetooth client
Free heap 96196
49031[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
49071[HTR] 76 16 02 01 00 82 0B A4 00 33 00 12 00 59 03 BF 1A 00 00 1B 64 00 14 02
No Bluetooth client
Free heap 96196
50053[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
50093[HTR] 76 16 02 01 00 82 0B B8 00 33 00 13 00 59 03 BB 1A 00 00 1B 64 00 21 5F
No Bluetooth client
Free heap 96196
51076[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
51116[HTR] 76 16 02 01 00 82 0B C2 00 34 00 13 00 59 03 BB 1A 00 00 1B 64 00 45 AE
No Bluetooth client
Free heap 96196
52099[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
52139[HTR] 76 16 02 01 00 82 0B E0 00 34 00 13 00 59 03 BF 1A 00 00 1B 64 00 9C 49
No Bluetooth client
Free heap 96196
53122[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
53162[HTR] 76 16 02 01 00 7F 0B EA 00 32 00 13 00 59 03 BB 1B 00 00 1B 64 00 EC 5E
No Bluetooth client
Free heap 96196
54145[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
54185[HTR] 76 16 02 01 00 82 0C 08 00 35 00 13 00 59 03 C3 1B 00 00 1B 64 00 77 5D
No Bluetooth client
Free heap 96196
55167[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
55207[HTR] 76 16 02 01 00 82 0C 1C 00 36 00 13 00 59 03 BB 1B 00 00 1B 64 00 BC B4
No Bluetooth client
Free heap 96196
56187[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
56227[HTR] 76 16 02 01 00 81 0C 3A 00 36 00 13 00 59 03 BF 1B 00 00 1B 64 00 96 A7
No Bluetooth client
Free heap 96196
57207[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
57247[HTR] 76 16 02 01 00 82 0C 58 00 36 00 13 00 59 03 BB 1C 00 00 1B 64 00 38 F1
No Bluetooth client
Free heap 96196
58230[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
58270[HTR] 76 16 02 01 00 82 0C 6C 00 37 00 13 00 59 03 BB 1C 00 00 1B 64 00 AE C7
No Bluetooth client
Free heap 96196

File diff suppressed because it is too large Load diff

View file

@ -1,265 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "BluetoothHC05.h"
#include "../cfg/pins.h"
#include "../cfg/BTCConfig.h"
#include "../Protocol/Protocol.h"
#include "../Protocol/helpers.h"
#include "../Utility/DebugPort.h"
// Bluetooth access via HC-05 Module, using a UART
CBluetoothHC05::CBluetoothHC05(int keyPin, int sensePin)
{
// extra control pins required to fully drive a HC05 module
_keyPin = keyPin; // used to enable AT command mode (ONLY ON SUPPORTED MODULES!!!!)
_sensePin = sensePin; // feedback signal used to sense if a client is connected
pinMode(_keyPin, OUTPUT);
digitalWrite(_keyPin, LOW); // request HC-05 module to enter data mode
// attach to the SENSE line from the HC-05 module
// this line goes high when a BT client is connected :-)
pinMode(_sensePin, INPUT);
}
void
CBluetoothHC05::begin()
{
const int BTRates[] = {
9600, 38400, 115200, 19200, 57600, 2400, 4800, 1200
};
_rxLine.clear();
digitalWrite(_keyPin, HIGH); // request HC-05 module to enter command mode
delay(50);
openSerial(9600); // virtual function, may call derived class method here
DebugPort.println("\r\n\r\nAttempting to detect HC-05 Bluetooth module...");
int BTidx = 0;
int maxTries = sizeof(BTRates)/sizeof(int);
for(BTidx = 0; BTidx < maxTries; BTidx++) {
DebugPort.print(" @ ");
DebugPort.print(BTRates[BTidx]);
DebugPort.print(" baud... ");
openSerial(BTRates[BTidx]); // open serial port at a std. baud rate
delay(10);
flush();
HC05_SerialPort.print("AT\r\n"); // clear the throat!
delay(100);
HC05_SerialPort.setTimeout(100);
if(ATCommand("AT\r\n")) { // probe with a simple "AT"
DebugPort.println(" OK."); // got a response - woo hoo found the module!
break;
}
if(ATCommand("AT\r\n")) { // sometimes a second try is good...
DebugPort.println(" OK.");
break;
}
// failed, try another baud rate
DebugPort.println("");
HC05_SerialPort.flush();
HC05_SerialPort.end();
delay(100);
}
DebugPort.println("");
if(BTidx == maxTries) {
// we could not get anywhere with the AT commands, but maybe this is the other module
// plough on and assume 9600 baud, but at the mercy of whatever the module name is...
DebugPort.println("FAILED to detect a HC-05 Bluetooth module :-(");
// leave the EN pin high - if other style module keeps it powered!
// assume it is 9600, and just (try to) use it like that...
// we will sense the STATE line to prove a client is hanging off the link...
DebugPort.println("ASSUMING a HC-05 module @ 9600baud (Unknown name)");
openSerial(9600);
}
else {
// found a HC-05 module at one of its supported baud rates.
// now program it's name and force a 9600 baud data interface.
// this is the defacto standard as shipped!
DebugPort.println("HC-05 found");
DebugPort.print(" Setting Name to \"Afterburner\"... ");
if(!ATCommand("AT+NAME=\"Afterburner\"\r\n")) {
DebugPort.println("FAILED");
}
else {
DebugPort.println("OK");
}
DebugPort.print(" Setting baud rate to 9600N81...");
if(!ATCommand("AT+UART=9600,1,0\r\n")) {
DebugPort.println("FAILED");
}
else {
DebugPort.println("OK");
}
DebugPort.print(" Lowering power consumption...");
if(!ATCommand("AT+IPSCAN=1024,1,1024,1\r\n")) {
DebugPort.println("FAILED");
}
else {
DebugPort.println("OK");
}
/*
DebugPort.print(" Lowering power consumption...");
if(!ATCommand("AT+SNIFF=40,20,1,8\r\n")) {
DebugPort.println("FAILED");
}
else {
DebugPort.println("OK");
}
DebugPort.print(" Lowering power consumption...");
if(!ATCommand("AT+ENSNIFF=0002,72,0A3C7F\r\n")) {
DebugPort.println("FAILED");
}
else {
DebugPort.println("OK");
}*/
flush();
delay(100);
openSerial(9600);
// leave HC-05 command mode, return to data mode
digitalWrite(_keyPin, LOW);
}
delay(50);
flush(); // ensure any AT command reponse dribbles are cleaned up!
DebugPort.println("");
}
void
CBluetoothHC05::check()
{
// check for data coming back over Bluetooth
if(HC05_SerialPort.available()) { // serial rx data is available
char rxVal = HC05_SerialPort.read();
collectRxData(rxVal);
}
}
bool
CBluetoothHC05::isConnected()
{
return digitalRead(_sensePin);
}
void
CBluetoothHC05::send(const char* Str)
{
if(isConnected()) {
HC05_SerialPort.print(Str);
}
else {
// DebugPort.print("No Bluetooth client");
}
}
/*
void
CBluetoothHC05::sendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
{
// report to debug port
CBluetoothAbstract::sendFrame(pHdr, Frame, false);
if(isConnected()) {
if(Frame.verifyCRC()) {
// send data frame to HC-05
HC05_SerialPort.print(pHdr);
HC05_SerialPort.write(Frame.Data, 24);
// toggle LED
#if BT_LED == 1
digitalWrite(LED_Pin, !digitalRead(LED_Pin)); // toggle LED
#endif
}
else {
DebugPort.print("Bluetooth data not sent, CRC error ");
}
}
else {
if(lineterm) { // only report no client if this will be at end of line (long line support)
DebugPort.print("No Bluetooth client");
}
// force LED off
#if BT_LED == 1
digitalWrite(LED_Pin, LOW);
#endif
}
if(lineterm)
DebugPort.println("");
}
*/
void
CBluetoothHC05::openSerial(int baudrate)
{
// standard serial port for Due, Mega (ESP32 uses virtual, derived from this class)
HC05_SerialPort.begin(baudrate);
}
// protected function, to perform Hayes commands with HC-05
bool
CBluetoothHC05::ATCommand(const char* cmd)
{
flush(); // ensure response is for *this* command!
HC05_SerialPort.print(cmd);
char RxBuffer[16];
memset(RxBuffer, 0, 16);
int read = HC05_SerialPort.readBytesUntil('\n', RxBuffer, 16); // \n is not included in returned string!
if((read == 3) && (0 == strcmp(RxBuffer, "OK\r")) ) {
return true;
}
return false;
}
void
CBluetoothHC05::foldbackDesiredTemp()
{
StaticJsonBuffer<32> jsonBuffer; // create a JSON buffer on the stack
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
if(foldbackModerator.addJson("TempDesired", getSetTemp(), root)) {
char opStr[32];
root.printTo(opStr);
send(opStr);
}
}
void
CBluetoothHC05::flush()
{
while(HC05_SerialPort.available())
HC05_SerialPort.read();
}

View file

@ -1,351 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "128x64OLED.h"
#include "fonts/tahoma16.h"
#include "fonts/tahoma24.h"
#include "fonts/Icons.h"
#include "BasicScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
#include "../Utility/NVStorage.h"
#define MAXIFONT tahoma_24ptFontInfo
//#define MAXIFONT tahoma_16ptFontInfo
///////////////////////////////////////////////////////////////////////////
//
// CBasicScreen
//
// This screen provides a basic control function
//
///////////////////////////////////////////////////////////////////////////
CBasicScreen::CBasicScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
{
_showSetModeTime = 0;
_showModeTime = 0;
_feedbackType = 0;
_nModeSel = 0;
}
bool
CBasicScreen::show()
{
CScreenHeader::show();
char msg[20];
int xPos, yPos;
float fTemp = getTemperatureSensor();
if(fTemp > -80) {
if(NVstore.getDegFMode()) {
fTemp = fTemp * 9 / 5 + 32;
sprintf(msg, "%.1f`F", fTemp);
}
else {
sprintf(msg, "%.1f`C", fTemp);
}
{
CTransientFont AF(_display, &MAXIFONT); // temporarily use a large font
_printMenuText(_display.xCentre(), 23, msg, false, eCentreJustify);
// _printMenuText(_display.xCentre(), 25, msg, false, eCentreJustify);
}
}
else {
_printMenuText(_display.xCentre(), 25, "No Temperature Sensor", false, eCentreJustify);
}
// at bottom of screen show either:
// Selection between Fixed or Thermostat mode
// Current heat demand setting
// Run state of heater
if(_showModeTime) {
const int border = 3;
const int radius = 4;
// Show selection between Fixed or Thermostat mode
long tDelta = millis() - _showModeTime;
if(tDelta < 0) {
yPos = _display.height() - _display.textHeight() - border; // bottom of screen, with room for box
// display "Fixed Hz" at lower right, allowing space for a selection surrounding box
strcpy(msg, "Fixed Hz");
xPos = _display.width() - border; // set X position to finish short of RHS
_printMenuText(xPos, yPos, msg, _nModeSel == 1, eRightJustify);
// display "Thermostat" at lower left, allowing space for a selection surrounding box
strcpy(msg, "Thermostat");
xPos = border;
_printMenuText(xPos, yPos, msg, _nModeSel == 0);
// setThermostatMode(_nModeSel == 0 ? 1 : 0); // set the new mode
}
else {
// cancel selection mode, apply whatever is boxed
_showModeTime = 0;
_showSetModeTime = millis() + 5000; // then make the new mode setting be shown
_feedbackType = 0;
_ScreenManager.reqUpdate();
}
}
if((_showModeTime == 0) && _showSetModeTime) {
long tDelta = millis() - _showSetModeTime;
if(tDelta < 0) {
switch(_feedbackType) {
case 0:
// Show current heat demand setting
if(getThermostatModeActive()) {
float fTemp = getTemperatureDesired();
if(NVstore.getDegFMode()) {
fTemp = fTemp * 9 / 5 + 32;
sprintf(msg, "Setpoint = %.0f`F", fTemp);
}
else {
sprintf(msg, "Setpoint = %.0f`C", fTemp);
}
}
else {
sprintf(msg, "Setpoint = %.1fHz", getHeaterInfo().getPump_Fixed());
}
break;
case 1:
case 2:
sprintf(msg, "GPIO output #%d %s", _feedbackType, getGPIO(_feedbackType-1) ? "ON" : "OFF");
break;
}
// centre message at bottom of screen
_printMenuText(_display.xCentre(), _display.height() - _display.textHeight(), msg, false, eCentreJustify);
}
else {
_showSetModeTime = 0;
}
}
if((_showModeTime == 0) && (_showSetModeTime == 0)) {
showRunState();
}
return true;
}
bool
CBasicScreen::keyHandler(uint8_t event)
{
static int repeatCount = -1;
if(event & keyPressed) {
repeatCount = 0; // unlock tracking of repeat events
}
//
// use repeat function for key hold detection
//
if(event & keyRepeat) {
if(repeatCount >= 0) {
repeatCount++;
// hold LEFT to toggle GPIO output #1
if(event & key_Left) {
if(repeatCount > 2) {
repeatCount = -1; // prevent double handling
setGPIO(0, !getGPIO(0)); // toggle GPIO output #1
_showSetModeTime = millis() + 2000;
_feedbackType = 1;
_ScreenManager.reqUpdate();
}
}
// hold RIGHT to toggle GPIO output #2
if(event & key_Right) {
if(repeatCount > 2) {
repeatCount = -1; // prevent double handling
setGPIO(1, !getGPIO(1)); // toggle GPIO output #2
_showSetModeTime = millis() + 2000;
_feedbackType = 2;
_ScreenManager.reqUpdate();
}
}
// hold DOWN to enter thermostat / fixed mode selection
if(event & key_Down) {
if(repeatCount > 2) {
repeatCount = -1; // prevent double handling
_showModeTime = millis() + 5000;
_nModeSel = getThermostatModeActive() ? 0 : 1;
}
}
// hold UP to toggle degC/degF mode selection
if(event & key_Up) {
if(repeatCount > 2) {
repeatCount = -1; // prevent double handling
_showModeTime = millis() + 5000;
NVstore.setDegFMode(NVstore.getDegFMode() ? 0 : 1);
}
}
// hold CENTRE to turn ON or OFF
if(event & key_Centre) {
int runstate = getHeaterInfo().getRunStateEx();
if(runstate) { // running, including cyclic mode idle
if(repeatCount > 5) {
repeatCount = -1;
requestOff();
}
}
else { // standard idle state
// standby, request ON
if(repeatCount > 3) {
repeatCount = -1;
requestOn();
}
}
}
}
}
//
// key released handling
//
if(event & keyReleased) {
if(!_showModeTime) {
// release DOWN key to reduce set demand, provided we are not in mode select
if(event & key_Down) {
if(reqTempDelta(-1)) {
_showSetModeTime = millis() + 2000;
_feedbackType = 0;
_ScreenManager.reqUpdate();
}
else
_reqOEMWarning();
}
// release UP key to increase set demand, provided we are not in mode select
if(event & key_Up) {
if(reqTempDelta(+1)) {
_showSetModeTime = millis() + 2000;
_feedbackType = 0;
_ScreenManager.reqUpdate();
}
else
_reqOEMWarning();
}
}
if(event & key_Left) {
if(repeatCount >= 0) {
if(!_showModeTime) {
_ScreenManager.prevMenu();
}
else {
if(hasOEMcontroller())
_reqOEMWarning();
else {
_showModeTime = millis() + 5000;
_nModeSel = 0;
setThermostatMode(1); // set the new mode
NVstore.save();
}
_ScreenManager.reqUpdate();
}
}
}
if(event & key_Right) {
if(repeatCount >= 0) {
if(!_showModeTime)
_ScreenManager.nextMenu();
else {
if(hasOEMcontroller())
_reqOEMWarning();
else {
_showModeTime = millis() + 5000;
_nModeSel = 1;
setThermostatMode(0); // set the new mode
NVstore.save();
}
_ScreenManager.reqUpdate();
}
}
}
// release CENTRE to accept new mode, and/or show current setting
if(event & key_Centre) {
if(repeatCount != -2) { // prevent after off commands
if(_showModeTime) {
_showModeTime = millis(); // force immediate cancellation of showmode (via screen update)
}
_showSetModeTime = millis() + 2000;
_feedbackType = 0;
}
_ScreenManager.reqUpdate();
}
repeatCount = -1;
}
return true;
}
void
CBasicScreen::showRunState()
{
int runstate = getHeaterInfo().getRunStateEx();
int errstate = getHeaterInfo().getErrState();
if(errstate) errstate--; // correct for +1 biased return value
static bool toggle = false;
const char* toPrint = NULL;
_display.setTextColor(WHITE, BLACK);
if(errstate && ((runstate == 0) || (runstate > 5))) {
// flash error code
char msg[16];
toggle = !toggle;
if(toggle) {
// create an "E-XX" message to display
sprintf(msg, "E-%02d", errstate);
}
else {
strcpy(msg, " ");
}
int xPos = _display.xCentre();
int yPos = _display.height() - 2*_display.textHeight();
_printMenuText(xPos, yPos, msg, false, eCentreJustify);
toPrint = getHeaterInfo().getErrStateStr();
}
else {
if(runstate) {
toPrint = getHeaterInfo().getRunStateStr();
// simplify starting states
switch(runstate) {
case 1:
case 2:
case 3:
case 4:
toPrint = "Starting";
break;
}
}
}
if(toPrint) {
// locate at bottom centre
_printMenuText(_display.xCentre(), _display.height() - _display.textHeight(), toPrint, false, eCentreJustify);
}
}

View file

@ -1,107 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "128x64OLED.h"
#include "FontDumpScreen.h"
#include "KeyPad.h"
///////////////////////////////////////////////////////////////////////////
//
// CFontDumpScreen
//
// This screen provides control over experimental features
//
///////////////////////////////////////////////////////////////////////////
static const int Lines[4] = { 24, 34, 44, 54 };
CFontDumpScreen::CFontDumpScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreen(display, mgr)
{
_initUI();
}
void
CFontDumpScreen::onSelect()
{
CScreen::onSelect();
}
void
CFontDumpScreen::_initUI()
{
_startChar = 0;
}
bool
CFontDumpScreen::show()
{
_display.clearDisplay();
char msg[8];
_printInverted(_display.xCentre(), 0, " Adafruit Font ", true, eCentreJustify);
int column = 15;
for(int i=0; i<16; i++) {
sprintf(msg, "%X", i);
_printMenuText(column, 12, msg);
column += 7;
}
for(int row = 0; row < 4; row++) {
int currentChar = row * 16 + _startChar;
sprintf(msg, "%02X", currentChar);
_printMenuText(0, Lines[row], msg);
column = 15;
for(int i=0; i<16; i++) {
msg[0] = currentChar++;
msg[1] = 0;
_printMenuText(column, Lines[row], msg);
column += 7;
}
}
_display.drawFastVLine(13, 12, 61, WHITE);
_display.drawFastHLine(0, 21, 128, WHITE);
return true;
}
bool
CFontDumpScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
// press LEFT or UP to show prior 64 characters
if(event & (key_Left | key_Up)) {
_startChar -= 64;
}
// press RIGHT or DOWN to show next 64 characters
if(event & (key_Right | key_Down)) {
_startChar += 64;
}
// CENTRE press
if(event & key_Centre) {
_ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::ExThermostatUI); // force return to prior menu
}
_ScreenManager.reqUpdate();
}
return true;
}

View file

@ -1,281 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
///////////////////////////////////////////////////////////////////////////
//
// CFuelMixtureScreen
//
// This screen allows the fuel mixture endpoints to be adjusted
//
///////////////////////////////////////////////////////////////////////////
#include "FuelMixtureScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Wifi/BTCWifi.h"
#include "../utility/debugPort.h"
CFuelMixtureScreen::CFuelMixtureScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
_initUI();
}
void
CFuelMixtureScreen::onSelect()
{
CPasswordScreen::onSelect();
_initUI();
adjPump[0] = getHeaterInfo().getPump_Min();
adjPump[1] = getHeaterInfo().getPump_Max();
adjFan[0] = getHeaterInfo().getFan_Min();
adjFan[1] = getHeaterInfo().getFan_Max();
}
void
CFuelMixtureScreen::_initUI()
{
_rowSel = 0;
_colSel = 0;
}
bool
CFuelMixtureScreen::show()
{
char str[16];
int xPos, yPos;
const int col2 = 90;
const int col3 = _display.width() - border;
_display.clearDisplay();
if(!CPasswordScreen::show()) {
switch(_rowSel) {
case 0:
case 1:
case 2:
case 3:
case 4:
// Pump Minimum adjustment
yPos = border + 36;
_printMenuText(80, yPos, "Min", false, eRightJustify);
sprintf(str, "%.1f", adjPump[0]);
_printMenuText(col3, yPos, str, _rowSel == 1, eRightJustify);
// Pump Maximum adjustment
yPos = border + 24;
_printMenuText(80, yPos, "Pump Hz Max", false, eRightJustify);
sprintf(str, "%.1f", adjPump[1]);
_printMenuText(col3, yPos, str, _rowSel == 2, eRightJustify);
// Fan Minimum adjustment
yPos = border + 12;
_printMenuText(80, yPos, "Min", false, eRightJustify);
sprintf(str, "%d", adjFan[0]);
_printMenuText(col3, yPos, str, _rowSel == 3, eRightJustify);
// Fan Maximum adjustment
yPos = border;
_printMenuText(80, yPos, "Fan RPM Max", false, eRightJustify);
sprintf(str, "%d", adjFan[1]);
_printMenuText(col3, yPos, str, _rowSel == 4, eRightJustify);
// navigation line
yPos = 53;
xPos = _display.xCentre();
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 Exit \020 ", _rowSel == 0, eCentreJustify); // " < Exit > "
break;
case 1:
case 2:
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(xPos, 56, "\030\031Sel Save \033\032 \3600.1", false, eCentreJustify); // "^vSel Save <> +-0.1"
break;
case 3:
case 4:
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(xPos, 56, "\030\031Sel Save \033\032 \36010", false, eCentreJustify); // "^vSel Save <> +-10"
break;
}
break;
case 5:
_printInverted(_display.xCentre(), 0, " Save Fuel Settings ", true, eCentreJustify);
_printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify);
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
break;
}
}
return true;
}
bool
CFuelMixtureScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
// press CENTRE
if(event & key_Centre) {
switch(_rowSel) {
case 0:
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop);
break;
case 1:
case 2:
case 3:
case 4:
_rowSel = 5; // enter save confirm mode
break;
case 5:
_rowSel = 0;
break;
}
}
// press LEFT
if(event & key_Left) {
switch(_rowSel) {
case 0:
_ScreenManager.prevMenu();
break;
case 1:
case 2:
case 3:
case 4:
_adjustSetting(-1);
break;
case 5:
_rowSel = 0;
break;
}
}
// press RIGHT
if(event & key_Right) {
switch(_rowSel) {
case 0:
_ScreenManager.nextMenu();
break;
case 1:
case 2:
case 3:
case 4:
_adjustSetting(+1);
break;
case 5:
_rowSel = 0;
break;
}
}
// press UP
if(event & key_Up) {
if(hasOEMcontroller())
_reqOEMWarning();
else {
switch(_rowSel) {
case 0:
// grab current settings upon entry to edit mode
adjPump[0] = getHeaterInfo().getPump_Min();
adjPump[1] = getHeaterInfo().getPump_Max();
adjFan[0] = getHeaterInfo().getFan_Min();
adjFan[1] = getHeaterInfo().getFan_Max();
case 1:
case 2:
case 3:
_rowSel++;
_colSel = 0;
UPPERLIMIT(_rowSel, 4);
break;
case 5:
_showStoringMessage();
setPumpMin(adjPump[0]);
setPumpMax(adjPump[1]);
setFanMin(adjFan[0]);
setFanMax(adjFan[1]);
saveNV();
_rowSel = 0;
break;
}
}
}
// press DOWN
if(event & key_Down) {
switch(_rowSel) {
case 1:
case 2:
case 3:
case 4:
_rowSel--;
_colSel = 0;
break;
case 5:
_rowSel = 0;
break;
}
}
_ScreenManager.reqUpdate();
}
if(event & keyRepeat) {
switch(_rowSel) {
case 1:
case 2:
case 3:
case 4:
int adj = 0;
if(event & key_Right) adj = +1;
if(event & key_Left) adj = -1;
if(adj) {
_adjustSetting(adj);
}
break;
}
_ScreenManager.reqUpdate();
}
return true;
}
void
CFuelMixtureScreen::_adjustSetting(int dir)
{
switch(_rowSel) {
case 1:
adjPump[0] += (float(dir) * 0.1f);
break;
case 2:
adjPump[1] += (float(dir) * 0.1f);
break;
case 3:
adjFan[0] += dir * 10;
break;
case 4:
adjFan[1] += dir * 10;
break;
}
LOWERLIMIT(adjPump[0], 0.5f);
UPPERLIMIT(adjPump[0], 10.f);
LOWERLIMIT(adjPump[1], 0.5f);
UPPERLIMIT(adjPump[1], 10.f);
LOWERLIMIT(adjFan[0], 1000);
UPPERLIMIT(adjFan[0], 5000);
LOWERLIMIT(adjFan[1], 1000);
UPPERLIMIT(adjFan[1], 5000);
}

View file

@ -1,386 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "128x64OLED.h"
#include "GPIOScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
#include "../Utility/NVStorage.h"
#include "../Utility/GPIO.h"
#include "fonts/Icons.h"
extern CGPIOout GPIOout;
extern CGPIOin GPIOin;
extern CGPIOalg GPIOalg;
///////////////////////////////////////////////////////////////////////////
//
// CGPIOScreen
//
// This screen provides control over GPIO features
//
///////////////////////////////////////////////////////////////////////////
static const int Line3 = 14;
static const int Line2 = 27;
static const int Line1 = 40;
//static const int Column = 58;
static const int Column = 38;
CGPIOScreen::CGPIOScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
_initUI();
_GPIOinMode = 0;
_GPIOoutMode = 0;
_GPIOalgMode = 0;
}
void
CGPIOScreen::onSelect()
{
CPasswordScreen::onSelect();
_initUI();
_GPIOinMode = NVstore.getGPIOinMode();
_GPIOoutMode = NVstore.getGPIOoutMode();
_GPIOalgMode = NVstore.getGPIOalgMode();
}
void
CGPIOScreen::_initUI()
{
_rowSel = 0;
_animateCount = 0;
}
bool
CGPIOScreen::show()
{
_display.clearDisplay();
if(!CPasswordScreen::show()) { // for showing "saving settings"
if(_rowSel == 4) {
_printInverted(_display.xCentre(), 0, " Saving Settings ", true, eCentreJustify);
_printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify);
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
}
else {
_printInverted(_display.xCentre(), 0, " GPIO Settings ", true, eCentreJustify);
_display.drawBitmap(10, 14, GPIOIcon, GPIOWidth, GPIOHeight, WHITE);
// _printMenuText(55, Line3, "Inputs:", false, eRightJustify);
// _printMenuText(55, Line2, "Outputs:", false, eRightJustify);
// _printMenuText(55, Line1, "Analogue:", false, eRightJustify);
{
const char* msgText = NULL;
switch(_GPIOinMode) {
case 0: msgText = "Disabled"; break;
case 1: msgText = "1-On 2-Off"; break;
case 2: msgText = "1-On 2-\352T"; break;
case 3: msgText = "1-On/Off"; break;
}
if(msgText)
_printMenuText(Column, Line3, msgText, _rowSel == 3);
}
{
const char* msgText = NULL;
switch(_GPIOoutMode) {
case 0: msgText = "Disabled"; break;
case 1: msgText = "1: Status LED"; break;
case 2: msgText = "1&2 User"; break;
}
if(msgText)
_printMenuText(Column, Line2, msgText, _rowSel == 2);
}
{
const char* msgText = NULL;
switch(_GPIOalgMode) {
case 0: msgText = "Disabled"; break;
case 1: msgText = "Ip1 allows"; break;
}
if(msgText)
_printMenuText(Column, Line1, msgText, _rowSel == 1);
}
}
}
return true;
}
bool
CGPIOScreen::animate()
{
if(_rowSel != 4) {
int yPos = 53;
int xPos = _display.xCentre();
const char* pMsg = NULL;
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
break;
case 1:
_display.drawFastHLine(0, 52, 128, WHITE);
switch(_GPIOalgMode) {
case 0: pMsg = " Analogue input is ignored. "; break;
case 1: pMsg = " Input 1 enables reading of analogue input to set temperature. "; break;
}
if(pMsg)
_scrollMessage(56, pMsg, _scrollChar);
break;
case 2:
_display.drawFastHLine(0, 52, 128, WHITE);
switch(_GPIOoutMode) {
case 0: pMsg = " Digital outputs are disabled. "; break;
case 1: pMsg = " Output1: LED status indicator. "; break;
case 2: pMsg = " Output 1&2: User controlled. "; break;
}
if(pMsg)
_scrollMessage(56, pMsg, _scrollChar);
break;
case 3:
_display.drawFastHLine(0, 52, 128, WHITE);
switch(_GPIOinMode) {
case 0: pMsg = " Digital inputs are disabled. "; break;
case 1: pMsg = " Input 1: Starts upon closure. Input 2: Stops upon closure. "; break;
case 2: pMsg = " Input 1: Starts when held closed, stops when opened. Input2: Max fuel when closed, min fuel when open. "; break;
case 3: pMsg = " Input 1: Starts or Stops upon closure. "; break;
}
if(pMsg)
_scrollMessage(56, pMsg, _scrollChar);
break;
}
return true;
}
return false;
}
bool
CGPIOScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
// press LEFT to select previous screen
if(event & key_Left) {
switch(_rowSel) {
case 0:
_ScreenManager.prevMenu();
break;
case 1:
case 2:
case 3:
_scrollChar = 0;
_adjust(-1);
break;
case 4:
_rowSel = 0; // abort save
break;
}
}
// press RIGHT to select next screen
if(event & key_Right) {
switch(_rowSel) {
case 0:
_ScreenManager.nextMenu();
break;
case 1:
case 2:
case 3:
_scrollChar = 0;
_adjust(+1);
break;
case 4:
_rowSel = 0; // abort save
break;
}
}
if(event & key_Down) {
_scrollChar = 0;
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
// UP press
if(event & key_Up) {
switch(_rowSel) {
case 0:
case 1:
case 2:
case 3:
_scrollChar = 0;
_rowSel++;
UPPERLIMIT(_rowSel, 3);
break;
case 4: // confirmed save
_showStoringMessage();
NVstore.setGPIOinMode(_GPIOinMode);
NVstore.setGPIOoutMode(_GPIOoutMode);
NVstore.setGPIOalgMode(_GPIOalgMode);
saveNV();
setupGPIO();
_rowSel = 0;
break;
}
}
// CENTRE press
if(event & key_Centre) {
switch(_rowSel) {
case 0:
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
break;
case 1:
case 2:
case 3:
_rowSel = 4;
break;
}
}
_ScreenManager.reqUpdate();
}
return true;
}
void
CGPIOScreen::_adjust(int dir)
{
switch(_rowSel) {
case 1: // analogue mode
_GPIOalgMode += dir;
UPPERLIMIT(_GPIOalgMode, 1);
LOWERLIMIT(_GPIOalgMode, 0);
break;
case 2: // outputs mode
_GPIOoutMode += dir;
ROLLLOWERLIMIT(_GPIOoutMode, 0, 2);
ROLLUPPERLIMIT(_GPIOoutMode, 2, 0);
break;
case 3:
_GPIOinMode += dir;
ROLLUPPERLIMIT(_GPIOinMode, 3, 0);
ROLLLOWERLIMIT(_GPIOinMode, 0, 3);
break;
}
}
CGPIOInfoScreen::CGPIOInfoScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
{
_keyRepeatCount = -1;
}
void
CGPIOInfoScreen::onSelect()
{
CScreenHeader::onSelect();
}
void
CGPIOInfoScreen::_initUI()
{
}
bool
CGPIOInfoScreen::show()
{
CScreenHeader::show();
char msg[16];
_display.writeFillRect(49, 18, 30, 12, WHITE);
_printInverted(64, 20, "GPIO", true, eCentreJustify);
_printMenuText(22, 18, "In", false, eCentreJustify);
_printMenuText(104, 18, "Out", false, eCentreJustify);
_printMenuText(11, 20, "1", false, eCentreJustify);
_printMenuText(34, 20, "2", false, eCentreJustify);
_printMenuText(91, 20, "1", false, eCentreJustify);
_printMenuText(118, 20, "2", false, eCentreJustify);
_printMenuText(55, Line1, "Analogue:", false, eRightJustify);
_display.drawBitmap(4, 29, GPIOin.getState(0) ? CloseIcon : OpenIcon, CloseIconWidth, CloseIconHeight, WHITE);
_display.drawBitmap(27, 29, GPIOin.getState(1) ? CloseIcon : OpenIcon, CloseIconWidth, CloseIconHeight, WHITE);
_display.drawBitmap(86, 29, GPIOout.getState(0) ? BulbOnIcon : BulbOffIcon, BulbOnIconWidth, BulbOnIconHeight, WHITE);
_display.drawBitmap(113, 29, GPIOout.getState(1) ? BulbOnIcon : BulbOffIcon, BulbOnIconWidth, BulbOnIconHeight, WHITE);
sprintf(msg, "%d", GPIOalg.getValue());
_printMenuText(58, Line1, msg);
_printMenuText(_display.xCentre(), 53, " \021 \020 ", true, eCentreJustify);
return true;
}
bool
CGPIOInfoScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
_keyRepeatCount = 0; // unlock tracking of repeat events
// UP press
if(event & key_Up) {
}
// CENTRE press
if(event & key_Centre) {
}
}
if(event & keyRepeat) {
if(_keyRepeatCount >= 0) {
_keyRepeatCount++;
// hold LEFT to toggle GPIO output #1
if(event & key_Left) {
if(_keyRepeatCount > 2) {
_keyRepeatCount = -1; // prevent double handling
setGPIO(0, !getGPIO(0)); // toggle GPIO output #1
}
}
// hold RIGHT to toggle GPIO output #2
if(event & key_Right) {
if(_keyRepeatCount > 2) {
_keyRepeatCount = -1; // prevent double handling
setGPIO(1, !getGPIO(1)); // toggle GPIO output #2
}
}
}
}
// release event
if(event & keyReleased) {
if(_keyRepeatCount == 0) { // short Up press - lower target
// press LEFT to select previous screen
if(event & key_Left) {
_ScreenManager.prevMenu();
}
// press RIGHT to select next screen
if(event & key_Right) {
_ScreenManager.nextMenu();
}
}
_keyRepeatCount = -1;
}
_ScreenManager.reqUpdate();
return true;
}

View file

@ -1,216 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "128x64OLED.h"
#include "HomeMenuSelScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
#include "../Utility/NVStorage.h"
#include "../Utility/GPIO.h"
#include "fonts/Icons.h"
CHomeMenuSelScreen::CHomeMenuSelScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
}
void
CHomeMenuSelScreen::onSelect()
{
CScreenHeader::onSelect();
_rowSel = 0;
_action = NVstore.getHomeMenu();
}
void
CHomeMenuSelScreen::_initUI()
{
}
bool
CHomeMenuSelScreen::show()
{
char msg[16];
_display.clearDisplay();
if(!CPasswordScreen::show()) { // for showing "saving settings"
if(_rowSel == 4) {
_printInverted(_display.xCentre(), 0, " Saving Settings ", true, eCentreJustify);
_printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify);
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
}
else {
_printInverted(_display.xCentre(), 0, " Home Menu Actions ", true, eCentreJustify);
// _printMenuText(66, 14, "On timeout:", false, eRightJustify);
_display.drawBitmap(30, 14, timeoutIcon, timeoutWidth, timeoutHeight, WHITE);
switch(_action.onTimeout) {
case 0: strcpy(msg, "Default"); break;
case 1: strcpy(msg, "Detailed"); break;
case 2: strcpy(msg, "Basic"); break;
case 3: strcpy(msg, "Clock"); break;
}
_printMenuText(50, 14, msg, _rowSel == 3);
// _printMenuText(66, 26, "On start:", false, eRightJustify);
_display.drawBitmap(32, 26, startIcon, startWidth, startHeight, WHITE);
switch(_action.onStart) {
case 0: strcpy(msg, "Default"); break;
case 1: strcpy(msg, "Detailed"); break;
case 2: strcpy(msg, "Basic"); break;
case 3: strcpy(msg, "Clock"); break;
}
_printMenuText(50, 26, msg, _rowSel == 2);
// _printMenuText(66, 38, "On stop:", false, eRightJustify);
_display.drawBitmap(31, 38, stopIcon, stopWidth, stopHeight, WHITE);
switch(_action.onStop) {
case 0: strcpy(msg, "Default"); break;
case 1: strcpy(msg, "Detailed"); break;
case 2: strcpy(msg, "Basic"); break;
case 3: strcpy(msg, "Clock"); break;
}
_printMenuText(50, 38, msg, _rowSel == 1);
/* if(_rowSel == 0)
_printMenuText(_display.xCentre(), 53, " \021 \030Edit Exit \020 ", true, eCentreJustify);
else {
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(_display.xCentre(), 56, "\030\031Sel \033\032 Adj", false, eCentreJustify);
_printMenuText(_display.xCentre(), 56, "Save", false, eCentreJustify);
}*/
}
}
return true;
}
bool
CHomeMenuSelScreen::animate()
{
if(_rowSel != 4) {
int yPos = 53;
int xPos = _display.xCentre();
const char* pMsg = NULL;
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
break;
case 1:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Menu to switch to when the heater stops. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 2:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Menu to switch to when the heater starts. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 3:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Menu to return to after no keypad activity. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
}
return true;
}
return false;
}
bool
CHomeMenuSelScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
// UP press
if(event & key_Up) {
if(_rowSel == 4) {
_showStoringMessage();
NVstore.setHomeMenu(_action);
saveNV();
_rowSel = 0;
}
else {
_scrollChar = 0;
_rowSel++;
UPPERLIMIT(_rowSel, 3);
}
}
// UP press
if(event & key_Down) {
_scrollChar = 0;
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
// CENTRE press
if(event & key_Centre) {
if(_rowSel == 0) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
}
else {
_rowSel = 4;
}
}
// LEFT press
if(event & key_Left) {
if(_rowSel == 0)
_ScreenManager.prevMenu();
else
adjust(-1);
}
// RIGHT press
if(event & key_Right) {
if(_rowSel == 0)
_ScreenManager.nextMenu();
else
adjust(+1);
}
}
_ScreenManager.reqUpdate();
return true;
}
void
CHomeMenuSelScreen::adjust(int dir)
{
switch(_rowSel) {
case 1:
_action.onStop += dir;
ROLLLOWERLIMIT(_action.onStop, 0, 3);
ROLLUPPERLIMIT(_action.onStop, 3, 0);
break;
case 2:
_action.onStart += dir;
ROLLLOWERLIMIT(_action.onStart, 0, 3);
ROLLUPPERLIMIT(_action.onStart, 3, 0);
break;
case 3:
_action.onTimeout += dir;
ROLLLOWERLIMIT(_action.onTimeout, 0, 3);
ROLLUPPERLIMIT(_action.onTimeout, 3, 0);
break;
}
}

View file

@ -1,235 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "128x64OLED.h"
#include "OtherOptionsScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
#include "../Utility/NVStorage.h"
#include "../Utility/GPIO.h"
#include "fonts/Icons.h"
COtherOptionsScreen::COtherOptionsScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
}
void
COtherOptionsScreen::onSelect()
{
CScreenHeader::onSelect();
_rowSel = 0;
_repeatCount = -1;
_frameRate = NVstore.getFrameRate();
_dispTimeout = NVstore.getDimTime();
_menuTimeout = 60000;
}
void
COtherOptionsScreen::_initUI()
{
}
bool
COtherOptionsScreen::show()
{
char msg[16];
_display.clearDisplay();
if(!CPasswordScreen::show()) { // for showing "saving settings"
if(_rowSel == 4) {
_printInverted(_display.xCentre(), 0, " Saving Settings ", true, eCentreJustify);
_printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify);
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
}
else {
_printInverted(_display.xCentre(), 0, " Time Intervals ", true, eCentreJustify);
// data frame refresh rate
_display.drawBitmap(15, 13, refreshIcon, refreshWidth, refreshHeight, WHITE);
sprintf(msg, "%dms", _frameRate);
_printMenuText(40, 14, msg, _rowSel == 3);
// display timeout
_display.drawBitmap(10, 26, displayTimeoutIcon, displayTimeoutWidth, displayTimeoutHeight, WHITE);
if(_dispTimeout) {
float mins = float(abs(_dispTimeout)) / 60000.f;
sprintf(msg, "%s %0.1f min%s", (_dispTimeout < 0) ? "Blank" : "Dim", mins, mins < 2 ? "" : "s");
_printMenuText(40, 26, msg, _rowSel == 2);
}
else
_printMenuText(40, 26, "Always on", _rowSel == 2);
// menu timeout
_display.drawBitmap(10, 38, menuTimeoutIcon, menuTimeoutWidth, menuTimeoutHeight, WHITE);
if(_menuTimeout) {
float mins = float(abs(_menuTimeout)) / 60000.f;
sprintf(msg, "Home %0.1f min%s", mins, mins < 2 ? "" : "s");
_printMenuText(40, 38, msg, _rowSel == 1);
}
else
_printMenuText(40, 38, "Disabled", _rowSel == 1);
/* if(_rowSel == 0)
_printMenuText(_display.xCentre(), 53, " \021 Exit \020 ", _rowSel == 0, eCentreJustify);
else {
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(_display.xCentre(), 56, "\030\031Sel \033\032 Adj", false, eCentreJustify);
_printMenuText(_display.xCentre(), 56, "Save", false, eCentreJustify);
}*/
}
}
return true;
}
bool
COtherOptionsScreen::animate()
{
if(_rowSel != 4) {
int yPos = 53;
int xPos = _display.xCentre();
const char* pMsg = NULL;
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
break;
case 1:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " No keypad activity returns to the home menu. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 2:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " No keypad activity either dims or blanks the display. Hold Left or Right to toggle Dim/Blank mode. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 3:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Define the polling rate of the bluewire communications. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
}
return true;
}
return false;
}
bool
COtherOptionsScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
_repeatCount = 0;
// UP press
if(event & key_Up) {
if(_rowSel == 4) {
_showStoringMessage();
NVstore.setFrameRate(_frameRate);
NVstore.setDimTime(_dispTimeout);
saveNV();
_rowSel = 0;
}
else {
_scrollChar = 0;
_rowSel++;
UPPERLIMIT(_rowSel, 3);
}
}
// UP press
if(event & key_Down) {
_scrollChar = 0;
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
// CENTRE press
if(event & key_Centre) {
if(_rowSel == 0) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
}
else {
_rowSel = 4;
}
}
}
if(event & keyRepeat) {
if(keyRepeat >= 0) {
_repeatCount++;
if(_repeatCount > 4) {
// LEFT or RIGHT hold
if(event & (key_Right | key_Left)) {
if(_rowSel == 2) {
_repeatCount = -1;
_dispTimeout = -_dispTimeout;
}
}
}
}
}
if(event & keyReleased) {
if(_repeatCount == 0) {
// LEFT short press
if(event & key_Left) {
if(_rowSel == 0)
_ScreenManager.prevMenu();
else
adjust(-1);
}
// RIGHT short press
if(event & key_Right) {
if(_rowSel == 0)
_ScreenManager.nextMenu();
else
adjust(+1);
}
}
}
_ScreenManager.reqUpdate();
return true;
}
void
COtherOptionsScreen::adjust(int dir)
{
switch(_rowSel) {
case 1:
_menuTimeout += dir * 30000;
LOWERLIMIT(_menuTimeout, 0);
UPPERLIMIT(_menuTimeout, 300000);
break;
case 2:
_dispTimeout += dir * 30000;
LOWERLIMIT(_dispTimeout, -600000);
UPPERLIMIT(_dispTimeout, 600000);
break;
case 3:
_frameRate += dir * 50;
LOWERLIMIT(_frameRate, 300);
UPPERLIMIT(_frameRate, 1500);
break;
}
}

View file

@ -1,252 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "PrimingScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/NVStorage.h"
///////////////////////////////////////////////////////////////////////////
//
// CPrimingScreen
//
// This screen allows the temperature control mode to be selected and
// allows pump priming
//
///////////////////////////////////////////////////////////////////////////
CPrimingScreen::CPrimingScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
{
_initUI();
}
void
CPrimingScreen::onSelect()
{
_stopPump();
_initUI();
}
void
CPrimingScreen::onExit()
{
_stopPump();
}
void
CPrimingScreen::_initUI()
{
_PrimeStop = 0;
_PrimeCheck = 0;
_rowSel = 0;
_colSel = 0;
}
bool
CPrimingScreen::show()
{
CScreenHeader::show();
CRect extents;
int yPos = 53;
// show next/prev menu navigation line
switch(_rowSel) {
case 0:
_printMenuText(_display.xCentre(), yPos, " \021 \030Edit \020 ", _rowSel == 0, eCentreJustify);
break;
case 1:
case 2:
_display.drawFastHLine(0, 53, 128, WHITE);
_printMenuText(_display.xCentre(), 57, "\030\031 Sel \033\032 Adj", false, eCentreJustify);
break;
case 3:
_display.drawFastHLine(0, 53, 128, WHITE);
if(_colSel == 2) {
_printMenuText(_display.xCentre(), 57, "\033\030\031 Stop", false, eCentreJustify);
}
else {
_printMenuText(_display.xCentre(), 57, "\032 Start \031 Sel", false, eCentreJustify);
}
break;
}
yPos = 40;
if(_rowSel == 1) {
// follow user desired setting, heater info is laggy
_printMenuText(border, yPos, "Thermostat", _colSel == 0);
_printMenuText(_display.width()-border, yPos, "Fixed Hz", _colSel == 1, eRightJustify);
}
else {
// follow actual heater settings
// int col = getHeaterInfo().isThermostat() ? 0 : 1;
int col = getThermostatModeActive() ? 0 : 1;
_printInverted(border, yPos, "Thermostat", col == 0);
_printInverted(_display.width()-border, yPos, "Fixed Hz", col == 1, eRightJustify);
}
yPos = 28;
if(_rowSel == 2) {
_printMenuText(border, yPos, "degC", _colSel == 0);
_printMenuText(_display.width()-border, yPos, "degF", _colSel == 1, eRightJustify);
}
else {
int col = NVstore.getDegFMode();
_printInverted(border, yPos, "degC", col == 0);
_printInverted(_display.width()-border, yPos, "degF", col == 1, eRightJustify);
}
// fuel pump priming menu
yPos = 16;
_printMenuText(border, yPos, "Pump");
if(_rowSel == 3) {
_printMenuText(40, yPos, "OFF", _colSel == 1);
if(_colSel != 2) {
if(!getHeaterInfo().getRunState()) { // prevent option if heater is running
_printMenuText(70, yPos, "ON"); // becomes Hz when actually priming
}
}
else {
float pumpHz = getHeaterInfo().getPump_Actual();
// recognise if heater has stopped pump, after an initial holdoff upon first starting
long tDelta = millis() - _PrimeCheck;
if(_PrimeCheck && tDelta > 0 && pumpHz < 0.1) {
_stopPump();
}
// test if time is up, stop priming if so
tDelta = millis() - _PrimeStop;
if(_PrimeStop && tDelta > 0) {
_stopPump();
}
if(_PrimeStop) {
char msg[16];
sprintf(msg, "%.1fHz", pumpHz);
_printMenuText(70, yPos, msg, true);
}
}
}
return true;
}
bool
CPrimingScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
// press LEFT
if(event & key_Left) {
switch(_rowSel) {
case 0:
_ScreenManager.prevMenu();
break;
case 1:
_colSel = 0;
setThermostatMode(1);
saveNV();
break;
case 2:
_colSel = 0;
NVstore.setDegFMode(0);
break;
case 3:
_colSel = 1;
break;
case 4: break;
}
}
// press RIGHT
if(event & key_Right) {
switch(_rowSel) {
case 0:
_ScreenManager.nextMenu();
break;
case 1:
_colSel = 1;
setThermostatMode(0);
saveNV();
break;
case 2:
_colSel = 1;
NVstore.setDegFMode(1);
break;
case 3:
if(!getHeaterInfo().getRunState())
_colSel = 2;
break;
case 4: break;
}
}
// press UP
if(event & key_Up) {
if(hasOEMcontroller())
_reqOEMWarning();
else {
_rowSel++;
UPPERLIMIT(_rowSel, 3);
if(_rowSel == 3)
_colSel = 1; // select OFF upon entry to priming menu
if(_rowSel == 2)
_colSel = NVstore.getDegFMode();
if(_rowSel == 1)
// _colSel = getHeaterInfo().isThermostat() ? 0 : 1;
_colSel = getThermostatModeActive() ? 0 : 1;
}
}
// press DOWN
if(event & key_Down) {
_rowSel--;
LOWERLIMIT(_rowSel, 0);
_colSel = 0;
if(_rowSel == 1)
// _colSel = getHeaterInfo().isThermostat() ? 0 : 1;
_colSel = getThermostatModeActive() ? 0 : 1;
if(_rowSel == 2)
_colSel = NVstore.getDegFMode();
}
// check if fuel priming was selected
if(_rowSel == 3 && _colSel == 2) {
reqPumpPrime(true);
_PrimeStop = millis() + 150000; // allow 2.5 minutes - much the same as the heater itself cuts out at
_PrimeCheck = millis() + 3000; // holdoff upon start before testing for heater shutting off pump
}
else {
_stopPump();
}
_ScreenManager.reqUpdate();
}
return true;
}
void
CPrimingScreen::_stopPump()
{
reqPumpPrime(false);
_PrimeCheck = 0;
_PrimeStop = 0;
if(_colSel == 2)
_colSel = 1;
}

View file

@ -1,292 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include <Arduino.h>
#include "ScreenHeader.h"
#include "../Protocol/Protocol.h"
#include "../Protocol/helpers.h"
#include "../Wifi/BTCWifi.h"
#include "../Bluetooth/BluetoothAbstract.h"
#include "../Utility/NVStorage.h"
#include "../RTC/Clock.h"
#include "fonts/Arial.h"
#include "fonts/Icons.h"
#include "fonts/MiniFont.h"
#include "../RTC/TimerManager.h"
#define MINIFONT miniFontInfo
#define X_BT_ICON 10
#define Y_BT_ICON 0
#define X_WIFI_ICON 19
#define Y_WIFI_ICON 0
#define X_CLOCK 50
#define Y_CLOCK 0
#define X_TIMER_ICON 83
#define Y_TIMER_ICON 0
#define X_BATT_ICON 103
#define Y_BATT_ICON 0
/*#define X_BT_ICON 20
#define Y_BT_ICON 0
#define X_WIFI_ICON 29
#define Y_WIFI_ICON 0
#define X_GPIO_ICON 9
#define X_CLOCK 56
#define Y_CLOCK 0
#define X_TIMER_ICON 84
#define Y_TIMER_ICON 0
#define X_BATT_ICON 103
#define Y_BATT_ICON 0*/
CScreenHeader::CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr) : CScreen(disp, mgr)
{
_clearUpAnimation = false;
_clearDnAnimation = false;
_colon = false;
}
bool
CScreenHeader::show()
{
_display.clearDisplay();
// standard header items
// Bluetooth
showBTicon();
// WiFi
showWifiIcon();
// battery
showBatteryIcon(getHeaterInfo().getBattVoltage());
// timers
int numTimers = showTimers();
// // GPIO
// showGPIO();
// clock
showTime(numTimers);
return true;
}
// Animate IN/OUT arrows against the WiFi icon, according to actual web server traffic:
// an IN (down) arrow is drawn if incoming data has been detected.
// an OUT (up) arrow is drawn if outgoing data has been sent.
//
// Each arrow is drawn for one animation interval with a minimum of one clear interval
// creating a clean flash on the display.
// Both arrows may appear in the same interval.
// The following is a typical sequence, relative to animation ticks, note the gap
// that always appears in the animation interval between either arrow shown:
//
// | | | | | | | | | | | | | | | | |
// _________^^^^^________________________________________^^^^^_________________________
// ______________vvvvv_____vvvvv_______________vvvvv_____vvvvv_____vvvvv_______________
bool
CScreenHeader::animate()
{
bool retval = false;
if((isWifiConnected() || isWifiAP()) && isWebClientConnected()) {
int xPos = X_WIFI_ICON + W_WIFI_ICON;
if(isWifiAP()) {
xPos += 4;
}
// UP arrow animation
//
int yPos = 0;
if(_clearUpAnimation) {
// arrow was drawn in the prior iteration, now erase it
_display.fillRect(xPos, yPos, W_WIFIIN_ICON, H_WIFIIN_ICON, BLACK);
retval = true;
_clearUpAnimation = false;
}
else if(hasWebServerSpoken(true)) {
// we have emitted data to the web client, show an UP arrow
_display.drawBitmap(xPos, yPos, wifiOutIcon, W_WIFIIN_ICON, H_WIFIIN_ICON, WHITE);
_clearUpAnimation = true; // clear arrow upon next iteration
retval = true;
}
// DOWN arrow animation
//
yPos = H_WIFI_ICON - H_WIFIIN_ICON + 1;
if(_clearDnAnimation) {
// arrow was drawn in the prior iteration, now erase it
_display.fillRect(xPos, yPos, W_WIFIOUT_ICON, H_WIFIOUT_ICON, BLACK);
retval = true;
_clearDnAnimation = false;
}
else if(hasWebClientSpoken(true)) {
// we have receievd data from the web client, show an DOWN arrow
_display.drawBitmap(xPos, yPos, wifiInIcon, W_WIFIOUT_ICON, H_WIFIOUT_ICON, WHITE);
_clearDnAnimation = true; // clear arrow upon next iteration
retval = true;
}
}
return retval; // true if we need to update the physical display
}
void
CScreenHeader::showBTicon()
{
if(getBluetoothClient().isConnected()) {
_display.drawBitmap(X_BT_ICON, Y_BT_ICON, BTicon, W_BT_ICON, H_BT_ICON, WHITE);
}
}
void
CScreenHeader::showWifiIcon()
{
if(isWifiConnected() || isWifiAP()) {
_display.drawBitmap(X_WIFI_ICON, Y_WIFI_ICON, wifiIcon, W_WIFI_ICON, H_WIFI_ICON, WHITE);
if(isWifiButton()) {
_display.fillRect(X_WIFI_ICON + 11, Y_WIFI_ICON + 5, 15, 7, BLACK);
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON+6);
switch(isWifiButton()) {
case 1: _display.print("CFG"); break;
case 2: _display.print("HTR"); break;
case 3: _display.print("ERS"); break;
}
}
else if(isWifiConfigPortal()) {
_display.fillRect(X_WIFI_ICON + 11, Y_WIFI_ICON + 5, 15, 7, BLACK);
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON+6);
// _display.print("PTL");
_display.print("CFG");
}
else if(isWifiAP()) {
_display.fillRect(X_WIFI_ICON + 11, Y_WIFI_ICON + 5, 10, 7, BLACK);
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON+6);
_display.print("AP");
}
if(NVstore.getOTAEnabled()) {
_display.fillRect(X_WIFI_ICON +11, Y_WIFI_ICON, 14, 6, BLACK);
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON);
_display.print("OTA");
}
}
}
void
CScreenHeader::showBatteryIcon(float voltage)
{
_display.drawBitmap(X_BATT_ICON, Y_BATT_ICON, BatteryIcon, W_BATT_ICON, H_BATT_ICON, WHITE);
char msg[16];
sprintf(msg, "%.1fV", voltage);
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(X_BATT_ICON + W_BATT_ICON/2,
Y_BATT_ICON + H_BATT_ICON + 2);
_display.printCentreJustified(msg);
// nominal 10.5 -> 13.5V bargraph
int Capacity = (voltage - 10.7) * 4;
if(Capacity < 0) Capacity = 0;
if(Capacity > 11) Capacity = 11;
_display.fillRect(X_BATT_ICON+2 + Capacity, Y_BATT_ICON+2, W_BATT_ICON-4-Capacity, 6, BLACK);
}
int
CScreenHeader::showTimers()
{
int nextTimer = CTimerManager::getNextTimer();
if(nextTimer) {
int xPos = X_TIMER_ICON;
_display.drawBitmap(xPos, Y_TIMER_ICON, largeTimerIcon, W_TIMER_ICON, H_TIMER_ICON, WHITE);
if(nextTimer & 0x80)
_display.drawBitmap(xPos-3, Y_TIMER_ICON, verticalRepeatIcon, verticalRepeatWidthPixels, verticalRepeatHeightPixels, WHITE);
CTransientFont AF(_display, &miniFontInfo); // temporarily use a mini font
if((nextTimer & 0x0f) >= 10)
_display.setCursor(xPos+4, Y_TIMER_ICON+8);
else
_display.setCursor(xPos+6, Y_TIMER_ICON+8);
_display.print(nextTimer & 0x0f);
return 1;
}
return 0;
}
void
CScreenHeader::showTime(int numTimers)
{
const BTCDateTime& now = Clock.get();
char msg[16];
if(now.day() == 0xA5) {
sprintf(msg, "No RTC");
}
else {
if(_colon)
sprintf(msg, "%02d:%02d", now.hour(), now.minute());
else
sprintf(msg, "%02d %02d", now.hour(), now.minute());
_colon = !_colon;
}
{
CTransientFont AF(_display, &arial_8ptFontInfo);
// determine centre position of remaining real estate
int xPos = X_WIFI_ICON + W_WIFI_ICON + W_WIFIIN_ICON; // rhs of wifi conglomeration
if(isWifiAP()) xPos += 4; // add more if an Access Point
/* switch(numTimers) {
case 0: xPos = _display.xCentre(); break;
case 1: xPos += (X_TIMER_ICON - xPos) / 2; break;
}
_printMenuText(xPos, Y_CLOCK, msg, false, eCentreJustify);*/
_printMenuText(X_CLOCK, Y_CLOCK, msg);
}
}
void
CScreenHeader::showGPIO()
{
/* int xPos = X_GPIO_ICON; // both are enabled - draw icon 1 to the left, otherwise leave to the right
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(xPos, 0);
_display.print("1");
_display.drawBitmap(xPos + 4, 0, getGPIO(0) ? TickIcon : CrossIcon, TickIconWidth, TickIconHeight, WHITE);
_display.setCursor(xPos, 6);
_display.print("2");
_display.drawBitmap(xPos + 4, 6, getGPIO(1) ? TickIcon : CrossIcon, TickIconWidth, TickIconHeight, WHITE);*/
}
/*void
CScreenHeader::showGPIO()
{
int xPos = X_GPIO_ICON; // both are enabled - draw icon 1 to the left, otherwise leave to the right
_display.drawBitmap(xPos, 0, getGPIO(0) ? GPIO1ONIcon : GPIO1OFFIcon, GPIOIconWidthPixels, GPIOIconHeightPixels, WHITE);
_display.drawBitmap(xPos, 8, getGPIO(1) ? GPIO2ONIcon : GPIO2OFFIcon, GPIOIconWidthPixels, GPIOIconHeightPixels, WHITE);
}*/

View file

@ -1,517 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "ScreenManager.h"
#include "DetailedScreen.h"
#include "BasicScreen.h"
#include "PrimingScreen.h"
#include "WiFiScreen.h"
#include "FuelMixtureScreen.h"
#include "SetClockScreen.h"
#include "SetTimerScreen.h"
#include "ClockScreen.h"
#include "RebootScreen.h"
#include "HeaterSettingsScreen.h"
#include "SettingsScreen.h"
#include "ThermostatModeScreen.h"
#include "FontDumpScreen.h"
#include "TimerChartScreen.h"
#include "InheritSettingsScreen.h"
#include "GPIOScreen.h"
#include "VersionInfoScreen.h"
#include "HomeMenuSelScreen.h"
#include "OtherOptionsScreen.h"
#include <Wire.h>
#include "../cfg/pins.h"
#include "../cfg/BTCConfig.h"
#include "../protocol/helpers.h"
#include "keypad.h"
#include "fonts/Icons.h"
#include "fonts/MiniFont.h"
////////////////////////////////////////////////////////////////////////////////////////////////
// splash creen created using image2cpp http://javl.github.io/image2cpp/
// Settings:
// Black background
// Invert [X]
// Arduino code, single bitmap
// Identifier: DieselSplash
// Draw Mode: Horizontal
//
const unsigned char DieselSplash [] PROGMEM = {
// 'Splash3, 128x64px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x18, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x06, 0x00, 0x00, 0x00, 0x00,
0x02, 0x3e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00,
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x08, 0x00, 0x00, 0x01, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x88, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x20, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x84, 0x00, 0x00,
0x00, 0x18, 0x00, 0x00, 0x20, 0x40, 0x00, 0x20, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x84, 0x00, 0x00,
0x00, 0x14, 0x00, 0x00, 0x40, 0x40, 0x00, 0x10, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x84, 0x00, 0x00,
0x00, 0x52, 0x00, 0x00, 0x40, 0x20, 0x00, 0x08, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00,
0x00, 0x34, 0x00, 0x00, 0x40, 0x10, 0x00, 0x04, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x18, 0x00, 0x00, 0x80, 0x10, 0x00, 0x02, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x34, 0x00, 0x00, 0x80, 0x08, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x52, 0x00, 0x00, 0x80, 0x08, 0x01, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x14, 0x00, 0x01, 0x00, 0x04, 0x3e, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x18, 0x00, 0x01, 0x00, 0x07, 0xc0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x10, 0x00, 0x06, 0x80, 0x1c, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0xc4, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x40, 0x64, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3c, 0x78, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3c, 0x40, 0x84, 0x00, 0x00, 0x01, 0x80, 0x00, 0x01, 0xc0, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x26, 0x23, 0x04, 0x00, 0x00, 0x00, 0x60, 0x00, 0x1e, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x43, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x01, 0xe0, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0xf8, 0x02, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x60, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x19, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0f, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0xf8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0xf8, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x1f, 0x20, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x03, 0xe8, 0x20, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x7c, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x08, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x46, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x50, 0x00, 0x00,
0x00, 0x02, 0x28, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x50, 0x00, 0x00,
0x00, 0x02, 0x28, 0x73, 0x2d, 0xc9, 0x5a, 0x8c, 0xb0, 0x20, 0x31, 0xdd, 0x66, 0x53, 0x2c, 0x00,
0x00, 0x03, 0xee, 0x44, 0xb1, 0x29, 0x63, 0x52, 0xc0, 0x20, 0x4a, 0x51, 0x89, 0x54, 0xb0, 0x00,
0x00, 0x02, 0x28, 0x47, 0xa1, 0x29, 0x42, 0x5e, 0x80, 0x20, 0x4a, 0x51, 0x09, 0x57, 0xa0, 0x00,
0x00, 0x02, 0x28, 0x44, 0x21, 0x2b, 0x42, 0x50, 0x80, 0x21, 0x4a, 0x51, 0x09, 0x54, 0x20, 0x00,
0x00, 0x02, 0x28, 0x33, 0x21, 0xc5, 0x42, 0x4c, 0x80, 0x1e, 0x32, 0x4d, 0x06, 0x53, 0x20, 0x00
};
CScreenManager::CScreenManager()
{
_pDisplay = NULL;
_menu = -1;
_subMenu = 0;
_rootMenu = -1;
_bReqUpdate = false;
_DimTime_ms = millis() + 60000;
_MenuTimeout = millis() + 60000;
_pRebootScreen = NULL;
_bDimmed = false;
}
CScreenManager::~CScreenManager()
{
for(int i=0; i < _Screens.size(); i++) {
for(int j=0; j < _Screens[i].size(); j++) {
if(_Screens[i][j]) {
delete _Screens[i][j];
_Screens[i][j] = NULL;
}
}
}
if(_pDisplay) {
delete _pDisplay; _pDisplay = NULL;
}
}
void
CScreenManager::begin(bool bNoClock)
{
// 128 x 64 OLED support (I2C)
// xxxx_SWITCHCAPVCC = generate display voltage from 3.3V internally
_pDisplay = new C128x64_OLED(OLED_SDA_pin, OLED_SCL_pin);
#if USE_ADAFRUIT_SH1106 == 1
_pDisplay->begin(SH1106_SWITCHCAPVCC);
Wire.begin(OLED_SDA_pin, OLED_SCL_pin, 800000); // speed up I2C from the default crappy 100kHz set via the adafruit begin!
#elif USE_ADAFRUIT_SSD1306 == 1
_pDisplay->begin(SSD1306_SWITCHCAPVCC, 0x3c);
_pDisplay->ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9
_pDisplay->ssd1306_command(0x1F); // correct lame reversal of OLED current phases
#endif
// replace adafruit splash screen
_pDisplay->clearDisplay();
_pDisplay->drawBitmap(0, 0, DieselSplash, 128, 64, WHITE);
_pDisplay->setCursor(90, 50);
CTransientFont AF(*_pDisplay, &miniFontInfo); // temporarily use a mini font
_pDisplay->setTextColor(WHITE);
_pDisplay->print(getVersionStr());
// Show initial display buffer contents on the screen --
_pDisplay->display();
DebugPort.println("Creating Screens");
std::vector<CScreen*> menuloop;
// create root menu loop
menuloop.push_back(new CDetailedScreen(*_pDisplay, *this)); // detail control
menuloop.push_back(new CBasicScreen(*_pDisplay, *this)); // basic control
if(!bNoClock)
menuloop.push_back(new CClockScreen(*_pDisplay, *this)); // clock
menuloop.push_back(new CPrimingScreen(*_pDisplay, *this)); // mode / priming
menuloop.push_back(new CWiFiScreen(*_pDisplay, *this)); // comms info
menuloop.push_back(new CGPIOInfoScreen(*_pDisplay, *this)); // GPIO info
menuloop.push_back(new CSettingsScreen(*_pDisplay, *this)); // Tuning info
_Screens.push_back(menuloop);
// create timer screens loop
menuloop.clear();
menuloop.push_back(new CTimerChartScreen(*_pDisplay, *this, 0)); // timer chart
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 0)); // set timer 1
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 1)); // set timer 2
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 2)); // set timer 3
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 3)); // set timer 4
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 4)); // set timer 5
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 5)); // set timer 6
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 6)); // set timer 7
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 7)); // set timer 8
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 8)); // set timer 9
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 9)); // set timer 10
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 10)); // set timer 11
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 11)); // set timer 12
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 12)); // set timer 13
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 13)); // set timer 14
_Screens.push_back(menuloop);
// create heater tuning screens loop - password protected
menuloop.clear();
menuloop.push_back(new CFuelMixtureScreen(*_pDisplay, *this)); // tuning
menuloop.push_back(new CHeaterSettingsScreen(*_pDisplay, *this)); // tuning
_Screens.push_back(menuloop);
// create User Settings screens loop
menuloop.clear();
menuloop.push_back(new CThermostatModeScreen(*_pDisplay, *this)); // experimental settings screen
menuloop.push_back(new CGPIOScreen(*_pDisplay, *this)); // GPIO settings screen
menuloop.push_back(new CVersionInfoScreen(*_pDisplay, *this)); // GPIO settings screen
menuloop.push_back(new CHomeMenuSelScreen(*_pDisplay, *this)); // Home menu settings screen
menuloop.push_back(new COtherOptionsScreen(*_pDisplay, *this)); // Other options screen
_Screens.push_back(menuloop);
// create branch screens
menuloop.clear();
menuloop.push_back(new CSetClockScreen(*_pDisplay, *this)); // clock set branch screen
menuloop.push_back(new CInheritSettingsScreen(*_pDisplay, *this)); // inherit OEM settings branch screen
menuloop.push_back(new CFontDumpScreen(*_pDisplay, *this)); // font dump branch screen
_Screens.push_back(menuloop);
_menu = 0;
#if RTC_USE_DS3231==0 && RTC_USE_DS1307==0 && RTC_USE_PCF8523==0
_rootMenu = 2; // bring up clock set screen first if using millis based RTC!
_subMenu = 2;
#else
_rootMenu = 1; // basic control screen
_subMenu = 1;
#endif
_enterScreen();
}
bool
CScreenManager::checkUpdate()
{
long dimTimeout = NVstore.getDimTime();
// manage dimming or blanking the display, according to user defined inactivity interval
if(dimTimeout && _DimTime_ms) {
long tDelta = millis() - _DimTime_ms;
if(tDelta > 0) {
// time to dim the display
_dim(true);
_DimTime_ms = 0;
if(dimTimeout < 0) {
_pDisplay->clearDisplay();
_pDisplay->display(); // blank screen
}
}
}
if(NVstore.getMenuTimeout() && _MenuTimeout) {
long tDelta = millis() - _MenuTimeout;
if(tDelta > 0) {
_MenuTimeout = 0;
// we will be blanking the display, transit through a dim stage first
if(dimTimeout < 0)
_dim(true);
_leaveScreen();
// fall back to main menu
selectMenu(RootMenuLoop);
// upon dim timeout - sticky root menu screens are the first 3 in the list:
// Detailed Control
// Basic Control
// Clock
// return to those upon timeout, otherwise return to Basic Control screen
if(_rootMenu > 2) {
uint8_t userHomeMenu = NVstore.getHomeMenu().onTimeout;
if(userHomeMenu) { // allow user to override defualt screen
userHomeMenu--;
DebugPort.print("Screen Manager: Menu timeout, falling back to user preferred screen: ");
switch(userHomeMenu) {
case 0: DebugPort.println("Detailed control menu"); break;
case 1: DebugPort.println("Basic control menu"); break;
case 2: DebugPort.println("Clock menu"); break;
}
_rootMenu = _subMenu = userHomeMenu;
}
else {
_rootMenu = _subMenu = 1;
DebugPort.print("Screen Manager: Menu timeout, falling back to Basic control screen");
}
}
_enterScreen();
}
}
static int prevRunState = -1;
int runState = getHeaterInfo().getRunStateEx();
if(runState != prevRunState) {
if(runState > 0 && prevRunState == 0) {
// heater has started
uint8_t userStartMenu = NVstore.getHomeMenu().onStart;
if(userStartMenu && userStartMenu <= 3) { // allow user to override defualt screen
userStartMenu--;
DebugPort.print("Screen Manager: Heater start detected, switching to user preferred screen: ");
switch(userStartMenu) {
case 0: DebugPort.println("Detailed control menu"); break;
case 1: DebugPort.println("Basic control menu"); break;
case 2: DebugPort.println("Clock menu"); break;
}
_rootMenu = _subMenu = userStartMenu;
_enterScreen();
}
}
if(runState == 0 && prevRunState != 0) {
// heater has stopped
uint8_t userStopMenu = NVstore.getHomeMenu().onStop;
if(userStopMenu && userStopMenu <= 3) { // allow user to override defualt screen
userStopMenu--;
DebugPort.print("Screen Manager: Heater stop detected, switching to user preferred screen: ");
switch(userStopMenu) {
case 0: DebugPort.println("Detailed control menu"); break;
case 1: DebugPort.println("Basic control menu"); break;
case 2: DebugPort.println("Clock menu"); break;
}
_rootMenu = _subMenu = userStopMenu;
_enterScreen();
}
}
prevRunState = runState;
}
if(_bReqUpdate) {
if((dimTimeout < 0) && (_DimTime_ms == 0)) {
// no screen updates, we should be blanked!
}
else {
if(_pRebootScreen) {
_pRebootScreen->show();
_bReqUpdate = false;
return true;
}
else {
if(_menu >= 0) {
_Screens[_menu][_subMenu]->show();
_bReqUpdate = false;
return true;
}
}
}
}
return false;
}
void
CScreenManager::reqUpdate()
{
_bReqUpdate = true;
}
bool
CScreenManager::animate()
{
if((NVstore.getDimTime() < 0) && (_DimTime_ms == 0)) {
// no screen updates, we should be blanked!
return false;
}
if(_menu >= 0)
return _Screens[_menu][_subMenu]->animate();
return false;
}
void
CScreenManager::refresh()
{
if(_pDisplay)
_pDisplay->display();
}
void
CScreenManager::_enterScreen()
{
if(_menu >= 0)
_Screens[_menu][_subMenu]->onSelect();
reqUpdate();
}
void
CScreenManager::_leaveScreen()
{
if(_menu >= 0)
_Screens[_menu][_subMenu]->onExit();
}
void
CScreenManager::_changeSubMenu(int dir)
{
_leaveScreen();
_subMenu += dir;
int bounds = _Screens[_menu].size() - 1;
ROLLUPPERLIMIT(_subMenu, bounds, 0);
ROLLLOWERLIMIT(_subMenu, 0, bounds);
if(_menu == 0)
_rootMenu = _subMenu; // track the root menu for when we branch then return
_enterScreen();
}
void
CScreenManager::nextMenu()
{
if(_menu >= 0 && _menu != BranchMenu) {
_changeSubMenu(+1);
}
}
void
CScreenManager::prevMenu()
{
if(_menu >= 0 && _menu != BranchMenu) {
_changeSubMenu(-1);
}
}
void
CScreenManager::keyHandler(uint8_t event)
{
long dimTime = NVstore.getDimTime();
if(_bDimmed) {
if(event & keyReleased) {
_dim(false);
_DimTime_ms = (millis() + abs(dimTime)) | 1;
_MenuTimeout = millis() + NVstore.getMenuTimeout();
}
return; // initial press when dimmed is always thrown away
}
// _dim(false);
_DimTime_ms = (millis() + abs(dimTime)) | 1;
_MenuTimeout = millis() + NVstore.getMenuTimeout();
// call key handler for active screen
if(_menu >= 0)
_Screens[_menu][_subMenu]->keyHandler(event);
}
void
CScreenManager::selectMenu(eUIMenuSets menuSet, int specific)
{
_leaveScreen();
if(_menu >= 0) { // only true once we have created the screens
_menu = menuSet;
if(specific >= 0) {
// targetting a specific menu
_subMenu = specific;
UPPERLIMIT(_subMenu, _Screens[_menu].size()-1); // check bounds!
}
else {
// default sub menu behaviour
if(_menu == 0)
_subMenu = _rootMenu; // return to last used root menu
else
_subMenu = 0; // branches always go to first sub menu
}
}
_enterScreen();
}
void
CScreenManager::showRebootMsg(const char* content[2], long delayTime)
{
if(_pRebootScreen == NULL)
_pRebootScreen = new CRebootScreen(*_pDisplay, *this);
_pRebootScreen->setMessage(content, delayTime);
_bReqUpdate = true;
_dim(false);
}
void
CScreenManager::showOTAMessage(int percent)
{
static int prevPercent = -1;
if(percent != prevPercent) {
_pDisplay->clearDisplay();
_pDisplay->setCursor(64,22);
_pDisplay->printCentreJustified("OTA update active");
if(percent) {
char msg[16];
sprintf(msg, "%d%%", percent);
_pDisplay->setCursor(64,32);
_pDisplay->printCentreJustified(msg);
}
prevPercent = percent;
_pDisplay->display();
}
}
void
CScreenManager::_dim(bool state)
{
_bDimmed = state;
_pDisplay->dim(state);
}

View file

@ -1,318 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "128x64OLED.h"
#include "ThermostatModeScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
#include "fonts/Icons.h"
#include "../Utility/NVStorage.h"
///////////////////////////////////////////////////////////////////////////
//
// CThermostatModeScreen
//
// This screen provides control over experimental features
//
///////////////////////////////////////////////////////////////////////////
static const int Line3 = 14;
static const int Line2 = 27;
static const int Line1 = 40;
static const int Column = 40;
CThermostatModeScreen::CThermostatModeScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
_initUI();
_window = 10;
_thermoMode = 0;
_cyclicMode.init();
}
void
CThermostatModeScreen::onSelect()
{
CPasswordScreen::onSelect();
_initUI();
_window = NVstore.getThermostatMethodWindow();
_thermoMode = NVstore.getThermostatMethodMode();
_cyclicMode = NVstore.getCyclicMode();
}
void
CThermostatModeScreen::_initUI()
{
_rowSel = 0;
_animateCount = 0;
_keyRepeat = -1;
}
bool
CThermostatModeScreen::show()
{
char msg[20];
_display.clearDisplay();
if(!CPasswordScreen::show()) { // for showing "saving settings"
if(_rowSel == 10) {
_printInverted(_display.xCentre(), 0, " Saving Settings ", true, eCentreJustify);
_printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify);
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
}
else {
_printInverted(_display.xCentre(), 0, " Thermostat Mode ", true, eCentreJustify);
_display.drawBitmap(3, 14, thermostatIcon, thermostatWidth, thermostatHeight, WHITE);
float fTemp = _window;
if(NVstore.getDegFMode()) {
fTemp = fTemp * 9 / 5;
sprintf(msg, "%.1f\367F", fTemp);
}
else {
sprintf(msg, "%.1f\367C", fTemp);
}
_printMenuText(Column, Line2, msg, _rowSel == 3);
switch(_thermoMode) {
case 1:
_printMenuText(Column, Line3, "Deadband", _rowSel == 4);
break;
case 2:
_printMenuText(Column, Line3, "Linear Hz", _rowSel == 4);
break;
default:
_printMenuText(Column, Line3, "Standard", _rowSel == 4);
break;
}
if(_cyclicMode.isEnabled()) {
float fTemp = _cyclicMode.Stop+1;
if(NVstore.getDegFMode()) {
fTemp = fTemp * 9 / 5;
sprintf(msg, "\352>%.0f\367F", fTemp);
}
else {
sprintf(msg, "\352>%.0f\367C", fTemp);
}
}
else {
strcpy(msg, "OFF");
}
_printMenuText(Column, Line1, msg, _rowSel == 1);
if(_cyclicMode.isEnabled()) {
float fTemp = _cyclicMode.Start;
if(NVstore.getDegFMode()) {
fTemp = fTemp * 9 / 5;
sprintf(msg, "\352<%.0f\367F", fTemp);
}
else {
sprintf(msg, "\352<%.0f\367C", fTemp);
}
}
else {
strcpy(msg, "");
}
_printMenuText(Column + 42, Line1, msg, _rowSel == 2);
}
}
return true;
}
bool
CThermostatModeScreen::animate()
{
if(_rowSel != 10) {
int yPos = 53;
int xPos = _display.xCentre();
const char* pMsg = NULL;
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
break;
case 1:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Heater shuts down over set point. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 2:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Heater restarts below setpoint. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 3:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " User defined window for custom thermostat modes. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 4:
_display.drawFastHLine(0, 52, 128, WHITE);
switch(_thermoMode) {
case 1:
pMsg = " The user defined window sets the thermostat's hysteresis. ";
break;
case 2:
pMsg = " The pump rate is adjusted linearly across the set point window. ";
break;
default:
pMsg = " Use heater's standard thermostat control. ";
break;
}
if(pMsg)
_scrollMessage(56, pMsg, _scrollChar);
break;
}
return true;
}
return false;
}
bool
CThermostatModeScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
_keyRepeat = 0; // unlock hold function
// press LEFT to select previous screen
if(event & key_Left) {
switch(_rowSel) {
case 0:
_ScreenManager.prevMenu();
break;
case 4:
_scrollChar = 0;
case 1:
case 2:
case 3:
_adjust(-1);
break;
case 10:
_rowSel = 0; // abort save
break;
}
}
// press RIGHT to select next screen
if(event & key_Right) {
switch(_rowSel) {
case 0:
_ScreenManager.nextMenu();
break;
case 4:
_scrollChar = 0;
case 1:
case 2:
case 3:
_adjust(+1);
break;
case 10:
_rowSel = 0; // abort save
break;
}
}
if(event & key_Down) {
if(_rowSel != 0) {
_scrollChar = 0;
_rowSel--;
if(_rowSel == 2 && !_cyclicMode.isEnabled())
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
}
// UP press
if(event & key_Up) {
switch(_rowSel) {
case 0:
case 1:
case 2:
case 3:
_scrollChar = 0;
_rowSel++;
if(_rowSel == 2 && !_cyclicMode.isEnabled())
_rowSel++;
UPPERLIMIT(_rowSel, 4);
break;
case 10: // confirmed save
_showStoringMessage();
NVstore.setThermostatMethodMode(_thermoMode);
NVstore.setThermostatMethodWindow(_window);
NVstore.setCyclicMode(_cyclicMode);
saveNV();
_rowSel = 0;
break;
}
}
// CENTRE press
if(event & key_Centre) {
switch(_rowSel) {
case 0:
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
break;
case 1:
case 2:
case 3:
case 4:
_rowSel = 10;
break;
}
}
_ScreenManager.reqUpdate();
}
if(event & keyRepeat) {
_keyRepeat++;
if((event & key_Down) && (keyRepeat >= 4)) {
_keyRepeat = -1;
if(_rowSel == 0) {
_ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::FontDumpUI);
}
}
}
if(event & keyReleased) {
_keyRepeat = -1;
}
return true;
}
void
CThermostatModeScreen::_adjust(int dir)
{
switch(_rowSel) {
case 1:
_cyclicMode.Stop += dir;
LOWERLIMIT(_cyclicMode.Stop, 0);
UPPERLIMIT(_cyclicMode.Stop, 10);
break;
case 2:
_cyclicMode.Start += dir;
LOWERLIMIT(_cyclicMode.Start, -10);
UPPERLIMIT(_cyclicMode.Start, 0);
break;
case 3: // window
_window += (dir * 0.1);
UPPERLIMIT(_window, 6.3);
LOWERLIMIT(_window, 0.2);
break;
case 4: // thermostat mode
_thermoMode += dir;
ROLLLOWERLIMIT(_thermoMode, 0, 2);
ROLLUPPERLIMIT(_thermoMode, 2, 0);
break;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,12 +0,0 @@
#include "FontTypes.h"
// Font data for Arial 8pt
extern const uint8_t PROGMEM arial_8ptBitmaps [];
extern const FONT_INFO arial_8ptFontInfo;
extern const FONT_CHAR_INFO PROGMEM arial_8ptDescriptors[];
// Font data for Arial 7pt
extern const uint8_t PROGMEM arial_7ptBitmaps [];
extern const FONT_INFO arial_7ptFontInfo;
extern const FONT_CHAR_INFO PROGMEM arial_7ptDescriptors[];

File diff suppressed because it is too large Load diff

View file

@ -1,14 +0,0 @@
#include "FontTypes.h"
// Font data for Franklin Gothic Medium Cond 8pt
extern const uint8_t PROGMEM franklinGothicMediumCond_8ptBitmaps [] ;
extern const FONT_CHAR_INFO PROGMEM franklinGothicMediumCond_8ptDescriptors[] ;
extern const FONT_INFO franklinGothicMediumCond_8ptFontInfo;
// Font data for Franklin Gothic Medium Cond 7pt
extern const uint8_t PROGMEM franklinGothicMediumCond_7ptBitmaps [];
extern const FONT_INFO franklinGothicMediumCond_7ptFontInfo;
extern const FONT_CHAR_INFO PROGMEM franklinGothicMediumCond_7ptDescriptors[];

View file

@ -1,539 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include <Arduino.h>
#include "Icons.h"
// 'Thermometer', 8x50px
const unsigned char bodyThermometerIcon [] PROGMEM = {
0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff,
0x7e, 0x3c
};
// 'ThermometerActual', 8x50px
const unsigned char ambientThermometerIcon [] PROGMEM = {
0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff,
0x7e, 0x3c
};
// 'ThermoPtr', 3x5px
const unsigned char thermoPtr [] PROGMEM = {
0x80, 0xc0, 0xe0, 0xc0, 0x80
};
// 'Bluetooth icon', 6x11px
const unsigned char BTicon [] PROGMEM = {
0x20, 0x30, 0x28, 0xa4, 0x68, 0x30, 0x68, 0xa4, 0x28, 0x30, 0x20,
};
// 'wifiIcon', 13x10px
const unsigned char wifiIcon [] PROGMEM = {
0x1f, 0xc0, 0x20, 0x20, 0x40, 0x10, 0x8f, 0x88, 0x10, 0x40, 0x20, 0x20,
0x07, 0x00, 0x08, 0x80, 0x00, 0x00, 0x02, 0x00
};
// 'wifiInIcon, 5x5px
const unsigned char wifiInIcon [] PROGMEM = {
0x70, 0x70, 0xf8, 0x70, 0x20
};
// 'wifiOutIcon, 5x5px
const unsigned char wifiOutIcon [] PROGMEM = {
0x20, 0x70, 0xf8, 0x70, 0x70
};
// 'BatteryIcon', 15x10px
const unsigned char BatteryIcon [] PROGMEM = {
0x30, 0x18, 0xff, 0xfe, 0x80, 0x02, 0xb6, 0xda, 0xb6, 0xda, 0xb6, 0xda, 0xb6, 0xda, 0xb6, 0xda,
0x80, 0x02, 0xff, 0xfe
};
// 'GlowPlugIcon', 16x9px
const unsigned char GlowPlugIcon [] PROGMEM = {
0x71, 0xc7, 0x0e, 0x38, 0x14, 0x14, 0x12, 0x24, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x0a, 0x28,
0x0e, 0x38
};
// 'HeatRise', 17x2px
const unsigned char GlowHeatIcon [] PROGMEM = {
0x80, 0x00, 0x80, 0x40, 0x01, 0x00
};
// 'Fan3_1a', 16x16px
const unsigned char FanIcon1 [] PROGMEM = {
0x03, 0xc0, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x03, 0xc0, 0x07, 0xe0, 0x06, 0x60,
0x7e, 0x7e, 0x87, 0xe1, 0x87, 0xe1, 0x84, 0x21, 0x84, 0x21, 0x78, 0x1e, 0x00, 0x00, 0x00, 0x00
};
// 'Fan3_2a', 16x16px
const unsigned char FanIcon2 [] PROGMEM = {
0x00, 0x78, 0x00, 0x84, 0x00, 0x84, 0x00, 0x84, 0x00, 0x84, 0x7b, 0xf8, 0x87, 0xe0, 0x86, 0x60,
0x86, 0x60, 0x87, 0xe0, 0x7b, 0xf8, 0x00, 0x84, 0x00, 0x84, 0x00, 0x84, 0x00, 0x84, 0x00, 0x78
};
// 'Fan3_3a', 16x16px
const unsigned char FanIcon3 [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x78, 0x1e, 0x84, 0x21, 0x84, 0x21, 0x87, 0xe1, 0x87, 0xe1, 0x7e, 0x7e,
0x06, 0x60, 0x07, 0xe0, 0x03, 0xc0, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x03, 0xc0
};
// 'Fan3_4a', 16x16px
const unsigned char FanIcon4 [] PROGMEM = {
0x1e, 0x00, 0x21, 0x00, 0x21, 0x00, 0x21, 0x00, 0x21, 0x00, 0x1f, 0xde, 0x07, 0xe1, 0x06, 0x61,
0x06, 0x61, 0x07, 0xe1, 0x1f, 0xde, 0x21, 0x00, 0x21, 0x00, 0x21, 0x00, 0x21, 0x00, 0x1e, 0x00
};
// 'FuelIcon', 7x12px
const unsigned char FuelIcon [] PROGMEM = {
0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38
};
// 'Target', 13x13px
const unsigned char TargetIcon [] PROGMEM = {
0x0f, 0x80, 0x10, 0x40, 0x20, 0x20, 0x47, 0x10, 0x88, 0x88, 0x92, 0x48, 0x97, 0x48, 0x92, 0x48,
0x88, 0x88, 0x47, 0x10, 0x20, 0x20, 0x10, 0x40, 0x0f, 0x80
};
// 'repeat', 15x15px
const unsigned char repeatIcon [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x02, 0xf0, 0x04, 0xe0, 0x04, 0xe0, 0x08, 0x98, 0x30, 0x07, 0xc0
};
// 'timerID1', 15x15px
const unsigned char timerID1Icon [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x09, 0x20, 0x11, 0x10, 0x21, 0x08, 0x2d, 0x08, 0x25, 0xe8,
0x24, 0x08, 0x24, 0x08, 0x10, 0x10, 0x08, 0x20, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00
};
// 'timerID2', 15x15px
const unsigned char timerID2Icon [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x09, 0x20, 0x11, 0x10, 0x21, 0x08, 0x2d, 0x08, 0x25, 0xe8,
0x28, 0x08, 0x2c, 0x08, 0x10, 0x10, 0x08, 0x20, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00
};
// 'timer', 15x15px
const unsigned char timerIcon [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x09, 0x20, 0x11, 0x10, 0x21, 0x08, 0x21, 0x08, 0x21, 0xe8,
0x20, 0x08, 0x20, 0x08, 0x10, 0x10, 0x08, 0x20, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00
};
// 'large timer', 15x15px
const unsigned char largeTimerIcon[] PROGMEM =
{
0x07, 0xC0, // #####
0x19, 0x30, // ## # ##
0x21, 0x08, // # # #
0x41, 0x04, // # # #
0x41, 0x04, // # # #
0x81, 0x02, // # # #
0x81, 0xF2, // # ##### #
0x80, 0x02, // # #
0x80, 0x02, // # #
0x80, 0x02, // # #
0x40, 0x04, // # #
0x40, 0x04, // # #
0x20, 0x08, // # #
0x18, 0x30, // ## ##
0x0F, 0xE0, // #######
};
const uint8_t PROGMEM verticalRepeatIcon [] =
{
0x78, // ####
0x38, // ###
0x38, // ###
0x48, // # #
0x80, // #
0x80, // #
0x80, // #
0x80, // #
0x80, // #
0x80, // #
0x80, // #
0x40, // #
0x40, // #
0x20, // #
0x20, // #
};
const uint8_t PROGMEM GPIO1OFFIcon[] =
{
0x3E, 0x00, // #####
0x41, 0x00, // # #
0x88, 0x80, // # # #
0x98, 0x80, // # ## #
0x88, 0x80, // # # #
0x88, 0x80, // # # #
0x9C, 0x80, // # ### #
0x41, 0x00, // # #
0x3E, 0x00, // #####
};
const uint8_t PROGMEM GPIO1ONIcon[] =
{
0x3E, 0x00, // #####
0x7F, 0x00, // #######
0xF7, 0x80, // #### ####
0xE7, 0x80, // ### ####
0xF7, 0x80, // #### ####
0xF7, 0x80, // #### ####
0xE3, 0x80, // ### ###
0x7F, 0x00, // #######
0x3E, 0x00, // #####
};
const uint8_t PROGMEM GPIO2OFFIcon[] =
{
0x3E, 0x00, // #####
0x41, 0x00, // # #
0x9C, 0x80, // # ### #
0x84, 0x80, // # # #
0x9C, 0x80, // # ### #
0x90, 0x80, // # # #
0x9C, 0x80, // # ### #
0x41, 0x00, // # #
0x3E, 0x00, // #####
};
const uint8_t PROGMEM GPIO2ONIcon[] =
{
0x3E, 0x00, // #####
0x7F, 0x00, // #######
0xE3, 0x80, // ### ###
0xFB, 0x80, // ##### ###
0xE3, 0x80, // ### ###
0xEF, 0x80, // ### #####
0xE3, 0x80, // ### ###
0x7F, 0x00, // #######
0x3E, 0x00, // #####
};
const uint8_t PROGMEM CrossIcon[] =
{
0x88, // # #
0x50, // # #
0x20, // #
0x50, // # #
0x88, // # #
};
const uint8_t PROGMEM TickIcon[] =
{
0x00, //
0x08, // #
0x10, // #
0xa0, // # #
0x40, // #
};
const uint8_t PROGMEM OpenIcon[] =
{
0x1F, 0xC0, // #######
0x02, 0x00, // #
0x02, 0x00, // #
0x3A, 0xE0, // ### # ###
0xEA, 0xB8, // ### # # # ###
0x3A, 0xE0, // ### # ###
0x00, 0x00, //
};
const uint8_t PROGMEM CloseIcon[] =
{
0x00, 0x00, //
0x00, 0x00, //
0x3F, 0xE0, // #########
0x3A, 0xE0, // ### # ###
0xFA, 0xF8, // ##### # #####
0x3A, 0xE0, // ### # ###
0x02, 0x00, // #
};
const uint8_t PROGMEM BulbOnIcon[] =
{
0x08, 0x00, // #
0x41, 0x00, // # #
0x1C, 0x00, // ###
0x22, 0x00, // # #
0xA2, 0x80, // # # # #
0x1C, 0x00, // ###
0x14, 0x00, // # #
0x1C, 0x00, // ###
};
const uint8_t PROGMEM BulbOffIcon[] =
{
0x00, 0x00, //
0x00, 0x00, //
0x1C, 0x00, // ###
0x22, 0x00, // # #
0x22, 0x00, // # #
0x1C, 0x00, // ###
0x14, 0x00, // # #
0x1C, 0x00, // ###
};
const uint8_t PROGMEM startIcon[] =
{
0x80, // #
0xC0, // ##
0xE0, // ###
0xF0, // ####
0xF8, // #####
0xF0, // ####
0xE0, // ###
0xC0, // ##
0x80, // #
};
const uint8_t PROGMEM stopIcon[] =
{
0x00, //
0xFC, // ######
0xFC, // ######
0xFC, // ######
0xFC, // ######
0xFC, // ######
0xFC, // ######
0x00, //
};
const uint8_t PROGMEM displayTimeoutIcon[] =
{
0xFF, 0xE1, 0xFF, // ########### #########
0x80, 0x20, 0x82, // # # # #
0x80, 0x20, 0x82, // # # # #
0x80, 0x20, 0x44, // # # # #
0x80, 0x20, 0x28, // # # # #
0x80, 0x20, 0x44, // # # # #
0xFF, 0xE0, 0x92, // ########### # # #
0x0E, 0x00, 0xBA, // ### # ### #
0x3F, 0x80, 0xFE, // ####### #######
0x00, 0x01, 0xFF, // #########
};
const uint8_t PROGMEM menuTimeoutIcon[] =
{
0x00, 0x01, 0xFF, // #########
0xFF, 0xC0, 0x82, // ########## # #
0x00, 0x00, 0x82, // # #
0xFF, 0x00, 0x44, // ######## # #
0x00, 0x00, 0x28, // # #
0xFC, 0x00, 0x44, // ###### # #
0x00, 0x00, 0x92, // # # #
0xFF, 0x80, 0xBA, // ######### # ### #
0x00, 0x00, 0xFE, // #######
0x00, 0x01, 0xFF, // #########
};
const uint8_t PROGMEM timeoutIcon[] =
{
0xFF, 0x80, // #########
0x41, 0x00, // # #
0x41, 0x00, // # #
0x22, 0x00, // # #
0x14, 0x00, // # #
0x22, 0x00, // # #
0x49, 0x00, // # # #
0x5D, 0x00, // # ### #
0x7F, 0x00, // #######
0xFF, 0x80, // #########
};
const uint8_t PROGMEM refreshIcon[] =
{
0x01, 0x00, // #
0x00, 0x80, // #
0x7F, 0xC8, // ######### #
0x80, 0x88, // # # #
0x81, 0x08, // # # #
0x80, 0x08, // # #
0x84, 0x08, // # # #
0x88, 0x08, // # # #
0x9F, 0xF0, // # #########
0x08, 0x00, // #
0x04, 0x00, // #
};
const uint8_t PROGMEM thermostatIcon[] =
{
0x00, 0x00, 0x07, 0x00, // ###
0x00, 0x00, 0x0E, 0x00, // ###
0x00, 0x00, 0x0C, 0x40, // ## #
0x00, 0x00, 0x0C, 0xC0, // ## ##
0x00, 0x00, 0x1F, 0xC0, // #######
0x00, 0x00, 0x3F, 0x80, // #######
0x00, 0x00, 0x7C, 0x00, // #####
0x00, 0x00, 0xF8, 0x00, // #####
0x38, 0x01, 0xF0, 0x00, // ### #####
0x44, 0x01, 0xE0, 0x00, // # # ####
0x44, 0x00, 0xC0, 0x00, // # # ##
0x45, 0xC0, 0x00, 0x00, // # # ###
0x44, 0x00, 0x00, 0x00, // # #
0x55, 0xC0, 0x08, 0x00, // # # # ### #
0x54, 0x00, 0x1C, 0x00, // # # # ###
0x55, 0xC0, 0x2A, 0x00, // # # # ### # # #
0x54, 0x00, 0x08, 0x00, // # # # #
0x54, 0x00, 0x00, 0x00, // # # #
0x54, 0x00, 0x08, 0x00, // # # # #
0x54, 0x00, 0x2A, 0x00, // # # # # # #
0x54, 0x00, 0x1C, 0x00, // # # # ###
0x54, 0x00, 0x08, 0x00, // # # # #
0x92, 0x00, 0x00, 0x00, // # # #
0xBA, 0x00, 0x00, 0x00, // # ### #
0xBA, 0x00, 0x00, 0x00, // # ### #
0xBA, 0x00, 0x00, 0x00, // # ### #
0x82, 0x00, 0x00, 0x00, // # #
0x7C, 0x00, 0x00, 0x80, // ##### #
0x00, 0x01, 0xB0, 0xC0, // ## ## ##
0x00, 0x01, 0xB0, 0xE0, // ## ## ###
0x00, 0x01, 0xB0, 0xF0, // ## ## ####
0x00, 0x01, 0xB0, 0xE0, // ## ## ###
0x00, 0x01, 0xB0, 0xC0, // ## ## ##
0x00, 0x00, 0x00, 0x80, // #
};
const uint8_t PROGMEM GPIOIcon[] =
{
0x00, 0x00, 0x00, //
0x00, 0x20, 0x00, // #
0x01, 0x20, 0x00, // # #
0x00, 0xA0, 0x70, // # # ###
0x3F, 0xE0, 0x10, // ######### #
0x00, 0xA5, 0x70, // # # # # ###
0x01, 0x22, 0x40, // # # # #
0x00, 0x25, 0x70, // # # # ###
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x20, 0x00, 0x00, // #
0x20, 0x80, 0x00, // # #
0x20, 0x40, 0x70, // # # ###
0x3F, 0xE0, 0x10, // ######### #
0x20, 0x45, 0x70, // # # # # ###
0x20, 0x82, 0x40, // # # # #
0x20, 0x05, 0x70, // # # # ###
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x08, 0x00, 0x00, // #
0x09, 0x00, 0x00, // # #
0x05, 0x00, 0x00, // # #
0x24, 0x08, 0x00, // # # #
0x02, 0x00, 0x00, // #
0x02, 0x00, 0x00, // #
0x01, 0x00, 0x00, // #
0xC3, 0x86, 0x00, // ## ### ##
0x01, 0x80, 0x00, // ##
/*
0x00, 0x00, //
0x00, 0x08, // #
0x00, 0x48, // # #
0x00, 0x28, // # #
0x0F, 0xF8, // #########
0x00, 0x28, // # #
0x00, 0x48, // # #
0x00, 0x08, // #
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x08, 0x00, // #
0x08, 0x20, // # #
0x08, 0x10, // # #
0x0F, 0xF8, // #########
0x08, 0x10, // # #
0x08, 0x20, // # #
0x08, 0x00, // #
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x08, 0x00, // #
0x09, 0x00, // # #
0x05, 0x00, // # #
0x24, 0x08, // # # #
0x02, 0x00, // #
0x02, 0x00, // #
0x01, 0x00, // #
0xC3, 0x86, // ## ### ##
0x01, 0x80, // ## */
};
const uint8_t PROGMEM firmwareIcon[] =
{
0xFF, 0xFF, 0xFF, 0xC0, // ##########################
0x80, 0x00, 0x00, 0x40, // # #
0x9F, 0xFF, 0x2A, 0x40, // # ############# # # # #
0x80, 0x00, 0x00, 0x40, // # #
0xFF, 0xFF, 0xFF, 0xC0, // ##########################
0x80, 0x00, 0x00, 0x40, // # #
0x80, 0x00, 0x00, 0x40, // # #
0x80, 0x7F, 0x00, 0x40, // # ####### #
0x80, 0x7F, 0x00, 0x40, // # ####### #
0x80, 0x7F, 0x00, 0x40, // # ####### #
0x80, 0x08, 0x00, 0x40, // # # #
0x80, 0x08, 0x00, 0x40, // # # #
0x83, 0xFF, 0xE0, 0x40, // # ############# #
0x82, 0x08, 0x20, 0x40, // # # # # #
0x82, 0x08, 0x20, 0x40, // # # # # #
0x8F, 0xBE, 0xF8, 0x40, // # ##### ##### ##### #
0x8F, 0xBE, 0xF8, 0x40, // # ##### ##### ##### #
0x8F, 0xBE, 0xF8, 0x40, // # ##### ##### ##### #
0x80, 0x00, 0x00, 0x40, // # #
0x80, 0x00, 0x00, 0x40, // # #
0xFF, 0xFF, 0xFF, 0xC0, // ##########################
};
const uint8_t PROGMEM hardwareIcon[] =
{
0xFF, 0xFF, // ################
0x80, 0x01, // # #
0x95, 0x09, // # # # # # #
0x95, 0x09, // # # # # # #
0xBF, 0x89, // # ####### # #
0xA0, 0x89, // # # # # #
0xA0, 0x81, // # # # #
0xA0, 0x81, // # # # #
0xA0, 0x81, // # # # #
0xA0, 0x89, // # # # # #
0xBF, 0x89, // # ####### # #
0x95, 0x09, // # # # # # #
0x95, 0x09, // # # # # # #
0x80, 0x01, // # #
0xFF, 0xFF, // ################
};

View file

@ -1,185 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
// 'Thermometer', 8x50px
#define W_BULB_ICON 8
#define H_BULB_ICON 50
extern const unsigned char ambientThermometerIcon [];
extern const unsigned char bodyThermometerIcon [];
// 'ThermoPtr', 3x5px
#define W_PTR_ICON 3
#define H_PTR_ICON 5
extern const unsigned char thermoPtr [];
// 'Bluetooth icon', 6x11px
#define W_BT_ICON 6
#define H_BT_ICON 11
extern const unsigned char BTicon [];
// 'wifiIcon', 13x10px
#define W_WIFI_ICON 13
#define H_WIFI_ICON 10
extern const unsigned char wifiIcon [];
// 'wifiInIcon', 5x5px
#define W_WIFIIN_ICON 5
#define H_WIFIIN_ICON 5
extern const unsigned char wifiInIcon [];
// 'wifiOutIcon', 5x5px
#define W_WIFIOUT_ICON 5
#define H_WIFIOUT_ICON 5
extern const unsigned char wifiOutIcon [];
// 'BatteryIcon', 15x10px
#define W_BATT_ICON 15
#define H_BATT_ICON 10
extern const unsigned char BatteryIcon [];
// 'GlowPlugIcon', 16x9px
#define W_GLOW_ICON 16
#define H_GLOW_ICON 9
extern const unsigned char GlowPlugIcon [];
// 'HeatRise', 17x2px
#define W_HEAT_ICON 17
#define H_HEAT_ICON 2
extern const unsigned char GlowHeatIcon [];
#define W_FAN_ICON 16
#define H_FAN_ICON 16
// 'Fan3_1a', 16x16px
extern const unsigned char FanIcon1 [];
// 'Fan3_2a', 16x16px
extern const unsigned char FanIcon2 [];
// 'Fan3_3a', 16x16px
extern const unsigned char FanIcon3 [];
// 'Fan3_4a', 16x16px
extern const unsigned char FanIcon4 [];
// 'FuelIcon', 7x12px
#define W_FUEL_ICON 7
#define H_FUEL_ICON 12
extern const unsigned char FuelIcon [];
// 'Target', 13x13px
#define W_TARGET_ICON 13
#define H_TARGET_ICON 13
extern const unsigned char TargetIcon [];
#define W_TIMER_ICON 15
#define H_TIMER_ICON 15
extern const unsigned char repeatIcon [];
extern const unsigned char timerID1Icon [];
extern const unsigned char timerID2Icon [];
extern const unsigned char timerIcon [];
extern const unsigned char largeTimerIcon [];
extern const uint8_t verticalRepeatIcon [];
extern const uint8_t GPIO1OFFIcon[];
extern const uint8_t GPIO1ONIcon[];
extern const uint8_t GPIO2OFFIcon[];
extern const uint8_t GPIO2ONIcon[];
extern const uint8_t CrossIcon[];
extern const uint8_t TickIcon[];
// Bitmap sizes for verticalRepeat
const uint8_t verticalRepeatWidthPixels = 6;
const uint8_t verticalRepeatHeightPixels = 15;
// Bitmap sizes for GPIOIcons
const uint8_t GPIOIconWidthPixels = 9;
const uint8_t GPIOIconHeightPixels = 9;
// Bitmap sizes for TickIcons
const uint8_t TickIconWidth = 5;
const uint8_t TickIconHeight = 5;
// Bitmap for open
extern const uint8_t OpenIcon[];
const uint8_t OpenIconWidth = 13;
const uint8_t OpenIconHeight = 7;
// Bitmap for close
extern const uint8_t CloseIcon[];
const uint8_t CloseIconWidth = 13;
const uint8_t CloseIconHeight = 7;
// Bitmap for BulbOn
extern const uint8_t BulbOnIcon[];
const uint8_t BulbOnIconWidth = 9;
const uint8_t BulbOnIconHeight = 8;
// Bitmap for BulbOff
extern const uint8_t BulbOffIcon[];
const uint8_t BulbOffIconWidth = 9;
const uint8_t BulbOffIconHeight = 8;
// Bitmap for start
extern const uint8_t startIcon[];
const uint8_t startWidth = 5;
const uint8_t startHeight = 9;
// Bitmap sizes for stop
extern const uint8_t stopIcon[];
const uint8_t stopWidth = 6;
const uint8_t stopHeight = 8;
// Bitmap for displayTimeout
extern const uint8_t displayTimeoutIcon[];
const uint8_t displayTimeoutWidth = 24;
const uint8_t displayTimeoutHeight = 10;
// Bitmap for menuTimeout
extern const uint8_t menuTimeoutIcon[];
const uint8_t menuTimeoutWidth = 24;
const uint8_t menuTimeoutHeight = 10;
// Bitmap for timeout
extern const uint8_t timeoutIcon[];
const uint8_t timeoutWidth = 9;
const uint8_t timeoutHeight = 10;
// Bitmap for refresh
extern const uint8_t refreshIcon[];
const uint8_t refreshWidth = 13;
const uint8_t refreshHeight = 11;
// Bitmap for thermostat modes
extern const uint8_t thermostatIcon[];
const uint8_t thermostatWidth = 28;
const uint8_t thermostatHeight = 34;
// Bitmap for gPIO
extern const uint8_t GPIOIcon[];
const uint8_t GPIOWidth = 20;
const uint8_t GPIOHeight = 33;
// Bitmap for firmware
extern const uint8_t firmwareIcon[];
const uint8_t firmwareWidth = 26;
const uint8_t firmwareHeight = 21;
// Bitmap for hardware
extern const uint8_t hardwareIcon[];
const uint8_t hardwareWidth = 16;
const uint8_t hardwareHeight = 15;

View file

@ -1,314 +0,0 @@
//
// Font data for Tahoma 16pt
//
// Generated by The Dot Factory:
// http://www.eran.io/the-dot-factory-an-lcd-font-and-image-generator/
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Dot Factory Settings
//
// Flip/Rotate Padding Removal Line Wrap Descriptors
// [X] Flip X Height(Y): Tightest (O) At column [X] Generate descriptor array
// [ ] Flip Y Width(X): Tightest ( ) At bitmap Char Width: In Bits
// 90deg Char Height: In Bits
// Font Height: In Bits
// Comments Byte [ ] Multiple descriptor arrays
// [X] Variable Name Bit layout: RowMajor
// [X] BMP visualise [#] Order: MSBfirst Create new when exceeds [80]
// [X] Char descriptor Format: Hex
// Style: Cpp Leading: 0x Image width: In Bits
// Image height: In Bits
// Variable name format
// Bitmaps: const uint8_t PROGMEM {0}Bitmaps Space char generation
// Char Info: const FONT_CHAR_INFO PROGMEM {0}Descriptors [ ] Generate space bitmap
// Font Info: const FONT_INFO {0}FontInfo [2] pixels for space char
// Width: const uint8_t {0}Width
// Height: const uint8_t {0}Height
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
#include "tahoma16.h"
// Character bitmaps for Tahoma 16pt
const uint8_t tahoma_16ptBitmaps[] PROGMEM =
{
// @0 '.' (4 pixels wide)
0x00, 0x0F, // ####
0x00, 0x0F, // ####
0x00, 0x0F, // ####
0x00, 0x0F, // ####
// @8 '0' (11 pixels wide)
0x0F, 0xF0, // ########
0x3F, 0xFC, // ############
0x7F, 0xFE, // ##############
0xFF, 0xFF, // ################
0xF0, 0x0F, // #### ####
0xE0, 0x07, // ### ###
0xF0, 0x0F, // #### ####
0xFF, 0xFF, // ################
0x7F, 0xFE, // ##############
0x3F, 0xFC, // ############
0x0F, 0xF0, // ########
// @30 '1' (10 pixels wide)
0x38, 0x07, // ### ###
0x38, 0x07, // ### ###
0x38, 0x07, // ### ###
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0x00, 0x07, // ###
0x00, 0x07, // ###
0x00, 0x07, // ###
// @50 '2' (11 pixels wide)
0x70, 0x07, // ### ###
0xE0, 0x0F, // ### ####
0xE0, 0x1F, // ### #####
0xE0, 0x3F, // ### ######
0xE0, 0x7F, // ### #######
0xF1, 0xF7, // #### ##### ###
0xFF, 0xE7, // ########### ###
0x7F, 0xC7, // ######### ###
0x7F, 0x87, // ######## ###
0x3E, 0x07, // ##### ###
0x00, 0x07, // ###
// @72 '3' (11 pixels wide)
0x70, 0x0E, // ### ###
0xF0, 0x0F, // #### ####
0xE0, 0x07, // ### ###
0xE3, 0x87, // ### ### ###
0xE3, 0x87, // ### ### ###
0xE3, 0x87, // ### ### ###
0xE7, 0xCF, // ### ##### ####
0xFF, 0xFF, // ################
0x7E, 0xFE, // ###### #######
0x7E, 0xFE, // ###### #######
0x3C, 0x78, // #### ####
// @94 '4' (12 pixels wide)
0x00, 0xF0, // ####
0x01, 0xF0, // #####
0x07, 0x70, // ### ###
0x0E, 0x70, // ### ###
0x38, 0x70, // ### ###
0x70, 0x70, // ### ###
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0x00, 0x70, // ###
0x00, 0x70, // ###
// @118 '5' (11 pixels wide)
0x00, 0x0E, // ###
0xFF, 0x87, // ######### ###
0xFF, 0x87, // ######### ###
0xFF, 0x87, // ######### ###
0xFF, 0x87, // ######### ###
0xE3, 0x87, // ### ### ###
0xE3, 0xCF, // ### #### ####
0xE3, 0xFF, // ### ##########
0xE3, 0xFE, // ### #########
0xE1, 0xFC, // ### #######
0xE0, 0xF8, // ### #####
// @140 '6' (11 pixels wide)
0x07, 0xF0, // #######
0x1F, 0xFC, // ###########
0x3F, 0xFE, // #############
0x7F, 0xFF, // ###############
0xFB, 0x0F, // ##### ## ####
0xF7, 0x07, // #### ### ###
0xE7, 0x8F, // ### #### ####
0xE7, 0xFF, // ### ###########
0xE7, 0xFE, // ### ##########
0xE3, 0xFC, // ### ########
0x01, 0xF8, // ######
// @162 '7' (11 pixels wide)
0xE0, 0x01, // ### #
0xE0, 0x07, // ### ###
0xE0, 0x1F, // ### #####
0xE0, 0x7F, // ### #######
0xE1, 0xFF, // ### #########
0xE7, 0xFC, // ### #########
0xFF, 0xF0, // ############
0xFF, 0xC0, // ##########
0xFF, 0x00, // ########
0xFC, 0x00, // ######
0xF0, 0x00, // ####
// @184 '8' (11 pixels wide)
0x3C, 0x3C, // #### ####
0x7E, 0xFE, // ###### #######
0x7F, 0xFE, // ##############
0xFF, 0xFF, // ################
0xE7, 0x8F, // ### #### ####
0xE3, 0x87, // ### ### ###
0xE3, 0xC7, // ### #### ###
0xFF, 0xFF, // ################
0x7F, 0xFE, // ##############
0x7E, 0xFE, // ###### #######
0x3C, 0x7C, // #### #####
// @206 '9' (11 pixels wide)
0x1F, 0x80, // ######
0x3F, 0xC7, // ######## ###
0x7F, 0xE7, // ########## ###
0xFF, 0xE7, // ########### ###
0xF1, 0xE7, // #### #### ###
0xE0, 0xEF, // ### ### ####
0xF0, 0xDF, // #### ## #####
0xFF, 0xFE, // ###############
0x7F, 0xFC, // #############
0x3F, 0xF8, // ###########
0x0F, 0xE0, // #######
// @228 '`' (8 pixels wide)
0x3C, 0x00, // ####
0x7E, 0x00, // ######
0xE7, 0x00, // ### ###
0xC3, 0x00, // ## ##
0xC3, 0x00, // ## ##
0xE7, 0x00, // ### ###
0x7E, 0x00, // ######
0x3C, 0x00, // ####
// @244 'C' (12 pixels wide)
0x07, 0xE0, // ######
0x1F, 0xF8, // ##########
0x3F, 0xFC, // ############
0x7F, 0xFE, // ##############
0xF8, 0x1F, // ##### #####
0xF0, 0x0F, // #### ####
0xE0, 0x07, // ### ###
0xE0, 0x07, // ### ###
0xE0, 0x07, // ### ###
0xE0, 0x07, // ### ###
0x70, 0x0E, // ### ###
0x78, 0x1E, // #### ####
// @268 ':' (4 pixels wide)
0x3C, 0x3C, // #### ####
0x3C, 0x3C, // #### ####
0x3C, 0x3C, // #### ####
0x3C, 0x3C, // #### ####
// @276 ' ' (4 pixels wide)
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
// @284 '-' (4 pixels wide)
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
// @300 'F' (9 pixels wide)
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xE3, 0x80, // ### ###
0xE3, 0x80, // ### ###
0xE3, 0x80, // ### ###
0xE3, 0x80, // ### ###
0xE3, 0x80, // ### ###
0xE3, 0x80, // ### ###
};
// Character descriptors for Tahoma 16pt
// { [Char width in bits], [Char height in bits], [Offset into tahoma_16ptCharBitmaps in bytes] }
const FONT_CHAR_INFO tahoma_16ptDescriptors[] PROGMEM =
{
{4, 16, 276}, // ' '
{0, 0, 0}, // '!'
{0, 0, 0}, // '"'
{0, 0, 0}, // '#'
{0, 0, 0}, // '$'
{0, 0, 0}, // '%'
{0, 0, 0}, // '&'
{0, 0, 0}, // '''
{0, 0, 0}, // '('
{0, 0, 0}, // ')'
{0, 0, 0}, // '*'
{0, 0, 0}, // '+'
{0, 0, 0}, // ,
{8, 16, 284}, // -
{4, 16, 0}, // '.'
{0, 0, 0}, // '/'
{11, 16, 8}, // '0'
{10, 16, 30}, // '1'
{11, 16, 50}, // '2'
{11, 16, 72}, // '3'
{12, 16, 94}, // '4'
{11, 16, 118}, // '5'
{11, 16, 140}, // '6'
{11, 16, 162}, // '7'
{11, 16, 184}, // '8'
{11, 16, 206}, // '9'
{4, 16, 268}, // ':'
{0, 0, 0}, // ';'
{0, 0, 0}, // '<'
{0, 0, 0}, // '='
{0, 0, 0}, // '>'
{0, 0, 0}, // '?'
{0, 0, 0}, // '@'
{0, 0, 0}, // 'A'
{0, 0, 0}, // 'B'
{12, 16, 244}, // 'C'
{0, 0, 0}, // 'D'
{0, 0, 0}, // 'E'
{10, 16, 300}, // 'F'
{0, 0, 0}, // 'G'
{0, 0, 0}, // 'H'
{0, 0, 0}, // 'I'
{0, 0, 0}, // 'J'
{0, 0, 0}, // 'K'
{0, 0, 0}, // 'L'
{0, 0, 0}, // 'M'
{0, 0, 0}, // 'N'
{0, 0, 0}, // 'O'
{0, 0, 0}, // 'P'
{0, 0, 0}, // 'Q'
{0, 0, 0}, // 'R'
{0, 0, 0}, // 'S'
{0, 0, 0}, // 'T'
{0, 0, 0}, // 'U'
{0, 0, 0}, // 'V'
{0, 0, 0}, // 'W'
{0, 0, 0}, // 'X'
{0, 0, 0}, // 'Y'
{0, 0, 0}, // 'Z'
{0, 0, 0}, // '['
{0, 0, 0}, // '\'
{0, 0, 0}, // ']'
{0, 0, 0}, // '^'
{0, 0, 0}, // '_'
{8, 16, 228}, // '`' use for degree symbol
};
// Font information for Tahoma 16pt
// easier to leave in RAM, not that big anyway
const FONT_INFO tahoma_16ptFontInfo =
{
16, // Character height
' ', // Start character
'`', // End character
2, // Width, in pixels, of space character
tahoma_16ptDescriptors, // Character descriptor array
tahoma_16ptBitmaps, // Character bitmap array
};

View file

@ -1,7 +0,0 @@
#include "FontTypes.h"
// Font data for Tahoma 16pt
extern const uint8_t tahoma_16ptBitmaps[] PROGMEM; // stored in program flash memory
extern const FONT_CHAR_INFO tahoma_16ptDescriptors[] PROGMEM; // stored in program flash memory
extern const FONT_INFO tahoma_16ptFontInfo;

View file

@ -1,251 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef _CPROTOCOL_H_
#define _CPROTOCOL_H_
#include <Arduino.h>
#include "../Utility/UtilClasses.h"
class CProtocol {
public:
union {
unsigned char Data[24];
struct {
unsigned char Byte0; // [0] always 0x76
unsigned char Len; // [1] always 0x16 == 22
unsigned char Command; // [2] transient commands: 00: NOP, 0xa0 START, 0x05: STOP
unsigned char ActualTemperature; // [3] 1degC / digit
unsigned char DesiredTemperature; // [4] 1degC / digit
unsigned char MinPumpFreq; // [5] 0.1Hz/digit
unsigned char MaxPumpFreq; // [6] 0.1Hz/digit
unsigned char MinFanRPM_MSB; // [7] 16 bit - big endian MSB
unsigned char MinFanRPM_LSB; // [8] 16 bit - big endian LSB : 1 RPM / digit
unsigned char MaxFanRPM_MSB; // [9] 16 bit - big endian MSB
unsigned char MaxFanRPM_LSB; // [10] 16 bit - big endian LSB : 1 RPM / digit
unsigned char OperatingVoltage; // [11] 120, 240 : 0.1V/digit
unsigned char FanSensor; // [12] SN-1 or SN-2
unsigned char OperatingMode; // [13] 0x32:Thermostat, 0xCD:Fixed
unsigned char MinTemperature; // [14] Minimum settable temperature
unsigned char MaxTemperature; // [15] Maximum settable temperature
unsigned char GlowDrive; // [16] power to supply to glow plug
unsigned char Prime; // [17] 00: normal, 0x5A: fuel prime
unsigned char Unknown1_MSB; // [18] always 0x01
unsigned char Unknown1_LSB; // [19] always 0x2c "300 secs = max run without burn detected"?
unsigned char Unknown2_MSB; // [20] always 0x0d
unsigned char Unknown2_LSB; // [21] always 0xac "3500 ?"
unsigned char CRC_MSB; // [22]
unsigned char CRC_LSB; // [23]
} Controller;
struct {
unsigned char Byte0; // always 0x76
unsigned char Len; // always 0x16 == 22 bytes
unsigned char RunState; // operating state
unsigned char ErrState; // 0: OFF, 1: ON, 2+ (E-0n + 1)
unsigned char SupplyV_MSB; // 16 bit - big endian MSB
unsigned char SupplyV_LSB; // 16 bit - big endian MSB : 0.1V / digit
unsigned char FanRPM_MSB; // 16 bit - big endian MSB
unsigned char FanRPM_LSB; // 16 bit - big endian LSB : 1 RPM / digit
unsigned char FanVoltage_MSB; // 16 bit - big endian MSB
unsigned char FanVoltage_LSB; // 16 bit - big endian LSB : 0.1V / digit
unsigned char HeatExchgTemp_MSB; // 16 bit - big endian MSB
unsigned char HeatExchgTemp_LSB; // 16 bit - big endian LSB : 1 degC / digit
unsigned char GlowPlugVoltage_MSB; // 16 bit - big endian MSB
unsigned char GlowPlugVoltage_LSB; // 16 bit - big endian LSB : 0.1V / digit
unsigned char GlowPlugCurrent_MSB; // 16 bit - big endian MSB
unsigned char GlowPlugCurrent_LSB; // 16 bit - big endian LSB : 10mA / digit
unsigned char ActualPumpFreq; // fuel pump freq.: 0.1Hz / digit
unsigned char StoredErrorCode; //
unsigned char Unknown1; // always 0x00
unsigned char FixedPumpFreq; // fixed mode frequency set point: 0.1Hz / digit
unsigned char Unknown2; // always 0x64 "100 ?"
unsigned char Unknown3; // always 0x00
unsigned char CRC_MSB;
unsigned char CRC_LSB;
} Heater;
};
static const int CtrlMode = 1;
static const int HeatMode = 2;
const unsigned short wCRCTable[256] = {
0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,
0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,
0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,
0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,
0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40,
0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41,
0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641,
0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040,
0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240,
0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441,
0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41,
0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840,
0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,
0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40,
0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640,
0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041,
0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240,
0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441,
0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41,
0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840,
0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41,
0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40,
0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640,
0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041,
0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241,
0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,
0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40,
0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841,
0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,
0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,
0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,
0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040
};
public:
CProtocol() { Init(0); };
CProtocol(int TxMode) { Init(TxMode); };
void Init(int Txmode);
// CRC handlers
unsigned short CalcCRC(int len) const; // calculate the CRC upon len bytes
void setCRC(); // calculate and set the CRC in the buffer
void setCRC(unsigned short CRC); // set the CRC in the buffer
unsigned short getCRC() const; // extract CRC value from buffer
bool verifyCRC(bool silent=false) const; // return true for CRC match
void setActiveMode() { Controller.Byte0 = 0x76; }; // this allows heater to save tuning params to EEPROM
void setPassiveMode() { Controller.Byte0 = 0x78; }; // this prevents heater saving tuning params to EEPROM
// command helpers
void resetCommand() { setRawCommand(0x00); };
void onCommand() { setRawCommand(0xA0); };
void offCommand() { setRawCommand(0x05); };
// raw command
int getRawCommand() const { return Controller.Command; };
void setRawCommand(int mode) { Controller.Command = mode; };
// Run state
unsigned char getRunState() const { return Heater.RunState; };
void setRunState(unsigned char state) { Heater.RunState = state; };
unsigned char getErrState() const { return Heater.ErrState; };
void setErrState(unsigned char state) { Heater.ErrState = state; };
unsigned char getStoredErrCode() const { return Heater.StoredErrorCode; };
void setStoredErrCode(unsigned char state) { Heater.StoredErrorCode = state; };
//
float getVoltage_Supply() const;
float getVoltage_SupplyRaw() const;
void setVoltage_Supply(float volts);
float getSystemVoltage() const { return float(Controller.OperatingVoltage) * 0.1; };
void setSystemVoltage(float val);
// fan set/get
short getFan_Actual() const; // Heater side, actual
short getFan_Min() const; // Controller side, define min fan speed
short getFan_Max() const; // Controller side, define max fan speed
void setFan_Actual(short speed); // Heater side, actual
void setFan_Min(short speed); // Controller side, define min fan speed
void setFan_Max(short speed); // Controller side, define max fan speed
float getFan_Voltage() const; // fan voltage
void setFan_Voltage(float volts); // fan voltage
// pump set/get
void setPump_Min(float Freq) { Controller.MinPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
void setPump_Max(float Freq) { Controller.MaxPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
void setPump_Actual(float Freq) { Heater.ActualPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
void setPump_Fixed(float Freq) { Heater.FixedPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
float getPump_Min() const { return float(Controller.MinPumpFreq) * 0.1f; }; // Tx side, min pump freq
float getPump_Max() const { return float(Controller.MaxPumpFreq) * 0.1f; }; // Tx side, max pump freq
float getPump_Actual() const { return float(Heater.ActualPumpFreq) * 0.1f; }; // Rx style, actual
float getPump_Fixed() const { return float(Heater.FixedPumpFreq) * 0.1f; }; // Fixed mode pump frequency
void setPump_Prime(bool on) { Controller.Prime = on ? 0x5A : 0; };
// temperature set/get
void setTemperature_Desired(unsigned char degC) { Controller.DesiredTemperature = degC; };
void setTemperature_Min(unsigned char degC) { Controller.MinTemperature = degC; };
void setTemperature_Max(unsigned char degC) { Controller.MaxTemperature = degC; };
void setTemperature_Actual(unsigned char degC) { Controller.ActualTemperature = degC; };
unsigned char getTemperature_Desired() const { return Controller.DesiredTemperature; };
unsigned char getTemperature_Min() const { return Controller.MinTemperature; };
unsigned char getTemperature_Max() const { return Controller.MaxTemperature; };
unsigned char getTemperature_Actual() const { return Controller.ActualTemperature; };
void setThermostatModeProtocol(unsigned on);
bool isThermostat() const { return Controller.OperatingMode == 0x32; };
// glow plug
float getGlowPlug_Current() const; // glow plug current
float getGlowPlug_Voltage() const; // glow plug voltage
void setGlowPlug_Current(short ampsx100); // glow plug current
void setGlowPlug_Voltage(short voltsx10); // glow plug voltage
void setGlowDrive(unsigned char val) { Controller.GlowDrive = val; };
unsigned char getGlowDrive() const { return Controller.GlowDrive; };
// heat exchanger
short getTemperature_HeatExchg() const; // temperature of heat exchanger
void setTemperature_HeatExchg(short degC); // temperature of heat exchanger
void DebugReport(const char* hdr, const char* ftr);
CProtocol& operator=(const CProtocol& rhs);
};
class CModeratedFrame : public CProtocol {
unsigned long lastTime;
public:
CModeratedFrame() { lastTime = 0; };
void setTime() { lastTime = millis(); };
long elapsedTime() { return millis() - lastTime; };
};
class CProtocolPackage {
CProtocol Heater;
CProtocol Controller;
CContextTimeStamp _timeStamp;
public:
void set(const CProtocol& htr, const CProtocol& ctl) { Heater = htr; Controller = ctl; };
int getRunState() const { return Heater.getRunState(); };
int getRunStateEx() const; // extra support for cyclic thermostat mode
const char* getRunStateStr() const;
int getErrState() const;
const char* getErrStateStr() const;
const char* getErrStateStrEx() const;
float getBattVoltage() const { return Heater.getVoltage_Supply(); };
bool isThermostat() const { return Controller.isThermostat(); };
float getTemperature_Desired() const { return float(Controller.getTemperature_Desired()); };
float getTemperature_HeatExchg() const { return float(Heater.getTemperature_HeatExchg()); };
float getTemperature_Min() const { return float(Controller.getTemperature_Min()); };
float getTemperature_Max() const { return float(Controller.getTemperature_Max()); };
float getPump_Fixed() const { return Heater.getPump_Fixed(); };
float getPump_Actual() const { return Heater.getPump_Actual(); };
float getPump_Min() const { return Controller.getPump_Min(); };
float getPump_Max() const { return Controller.getPump_Max(); };
float getFan_Actual() const { return Heater.getFan_Actual(); };
short getFan_Min() const { return Controller.getFan_Min(); };
short getFan_Max() const { return Controller.getFan_Max(); };
float getFan_Voltage() const { return Heater.getFan_Voltage(); };
int getFan_Sensor() const { return Controller.Controller.FanSensor; };
float getGlowPlug_Power() const { return Heater.getGlowPlug_Current() * Heater.getGlowPlug_Voltage(); };
float getGlow_Voltage() const { return Heater.getGlowPlug_Voltage(); };
float getGlow_Current() const { return Heater.getGlowPlug_Current(); };
float getSystemVoltage() const { return Controller.getSystemVoltage(); };
int getGlow_Drive() const { return Controller.getGlowDrive(); };
// void setRefTime();
void reportFrames(bool isOEM);
};
#endif

View file

@ -1,120 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "SmartError.h"
#include "TxManage.h"
CSmartError::CSmartError()
{
reset();
}
void
CSmartError::reset()
{
m_prevRunState = 0;
m_Error = 0;
m_bInhibit = false;
}
// we use inhibit when we manually command the heater off during preheat
// otherwise we'll register an ignition fail event
void
CSmartError::inhibit()
{
m_bInhibit = true;
m_Error = 0;
}
// accept a fresh heater frame
// inpsect the advertised run state, tracking when and how it transitions out
// of preheat especially.
// abnormal transitions are registered and becoem our smart m_Error
// In addition, the hetaer frame has the ErrState updated to track the
// smart error, providing no heater error exists!
void
CSmartError::monitor(const CProtocol& heaterFrame)
{
bool bSilent = true;
if(heaterFrame.verifyCRC(bSilent)) { // check but don't report dodgy frames to debug
// only accept valid heater frames!
monitor(heaterFrame.getRunState());
}
}
// test the new run state value, comparing to previous
// detect abnormal transitions
void
CSmartError::monitor(unsigned char newRunState)
{
// check if moving away from heater Idle state (S0)
// especially useful if an OEM controller exists
if((m_prevRunState == 0) && newRunState) {
// reset the smart error
m_Error = 0;
m_bInhibit = false;
}
if(!m_bInhibit) {
if(m_prevRunState == 2) { // preheat state (S2)
if(newRunState == 4) {
// transitioned from preheat to ignited
// - all good!
m_Error = 0;
}
else if(newRunState > 5) {
// transitioned from preheat to post glow
// - second ignition attempt failed, heater is shutting down
m_Error = 11;
}
else if(newRunState == 3) {
// transitioned from preheat to retry
// - first ignition attempt failed, heater will retry
m_Error = 12;
}
}
}
if(m_prevRunState != newRunState) {
// check for transition to startup
// - force cancellation of an on request if we generated it
if(newRunState >= 2) {
TxManage.queueOnRequest(false); // ensure ON request is cancelled
}
// check for transition to shutdown
// - force cancellation of an off request if we generated it
if(newRunState >= 7 || newRunState == 0) {
TxManage.queueOffRequest(false); // ensure OFF request is cancelled
}
}
m_prevRunState = newRunState;
}
// return our smart error, if it exists, as the registered code
unsigned char
CSmartError::getError()
{
if(m_Error) {
return m_Error;
}
return 0;
}

View file

@ -1,253 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "TxManage.h"
#include "../Utility/NVStorage.h"
#include "../Protocol/helpers.h"
//#define DEBUG_THERMOSTAT
extern void DebugReportFrame(const char* hdr, const CProtocol&, const char* ftr);
// CTxManage is used to send a data frame to the blue wire
//
// As the blue wire is bidirectional, we need to only allow our transmit data
// to reach the blue wire when we actually want to send data.
// At all other times we are listening to the blue wire, receiving any async data
//
// This requires external circuitry to toggle the Tx/Rx modes.
// A "Tx Gating" signal is used.
// when high, transmit data is sent to the blue wire
// when low, transmit data is blocked (Hi-Z)
//
// Ideally the circuit also prevents feeding back our own Tx data into the Rx pin
// but the main software loop handles this situation by only accepting Rx data when expected.
//
// Timing diagram
// ____________________
// Tx Gate ____________________| |___________________________
// _____________________________________________________________________
// Tx Data |||||||||||||||
CTxManage::CTxManage(int TxGatePin, HardwareSerial& serial) :
m_BlueWireSerial(serial),
m_TxFrame(CProtocol::CtrlMode)
{
m_bOnReq = false;
m_bOffReq = false;
m_bTxPending = false;
m_nStartTime = 0;
m_nTxGatePin = TxGatePin;
_rawCommand = 0;
}
void CTxManage::begin()
{
pinMode(m_nTxGatePin, OUTPUT);
digitalWrite(m_nTxGatePin, LOW); // default to receive mode
}
void
CTxManage::queueOnRequest(bool set)
{
m_bOnReq = set; // allow cancellation via heater response frame decode
m_bOffReq = false;
}
void
CTxManage::queueOffRequest(bool set)
{
m_bOffReq = set; // allow cancellation via heater response frame decode
m_bOnReq = false;
}
void
CTxManage::queueRawCommand(unsigned char val)
{
_rawCommand = val;
}
void
CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
{
// copy supplied frame, typically this will be the values an OEM controller delivered
// which means we parrot that data by default.
// When parroting, we must especially avoid ping ponging "set temperature"!
// Otherwise we are supplied with the default params for standalone mode, which we
// then instil the NV parameters
m_TxFrame = basisFrame;
// ALWAYS install on/off commands if required
#ifndef PROTOCOL_INVESTIGATION
m_TxFrame.resetCommand(); // no command upon blue wire initially, unless a request is pending
if(_rawCommand) {
m_TxFrame.setRawCommand(_rawCommand);
_rawCommand = 0;
}
else {
if(m_bOnReq) {
// m_bOnReq = false; // requires cancel via queueOnRequest(false)
m_TxFrame.onCommand();
}
if(m_bOffReq) {
// m_bOffReq = false; // requires cancel via queueOffRequest(false)
m_TxFrame.offCommand();
}
}
#endif
// 0x78 prevents the controller showing bum information when we parrot the OEM controller
// heater is happy either way, the OEM controller has set the max/min stuff already
if(isBTCmaster) {
m_TxFrame.setActiveMode(); // this allows heater to save the tuning params to EEPROM
m_TxFrame.setFan_Min(NVstore.getFmin());
m_TxFrame.setFan_Max(NVstore.getFmax());
m_TxFrame.setPump_Min(NVstore.getPmin());
m_TxFrame.setPump_Max(NVstore.getPmax());
float tActual = getTemperatureSensor();
uint8_t u8Temp = (uint8_t)(tActual);
m_TxFrame.setTemperature_Actual(u8Temp); // use current temp, for now
m_TxFrame.setTemperature_Desired(NVstore.getDesiredTemperature());
if(NVstore.getThermostatMode()) {
uint8_t ThermoMode = NVstore.getThermostatMethodMode(); // get the METHOD of thermostat control
float Window = NVstore.getThermostatMethodWindow();
float tCurrent = getTemperatureSensor();
float tDesired = float(NVstore.getDesiredTemperature());
float tDelta = tCurrent - tDesired;
float fTemp;
#ifdef DEBUG_THERMOSTAT
DebugPort.print("Window = "); DebugPort.print(Window); DebugPort.print(" tCurrent = "); DebugPort.print(tCurrent); DebugPort.print(" tDesired = "); DebugPort.print(tDesired); DebugPort.print(" tDelta = "); DebugPort.println(tDelta);
#endif
Window /= 2;
switch(ThermoMode) {
case 0: // conventional heater controlled thermostat mode
case 3: // conventional heater controlled thermostat mode
m_TxFrame.setThermostatModeProtocol(1); // using heater thermostat control
u8Temp = (uint8_t)(tActual + 0.5);
m_TxFrame.setTemperature_Actual(u8Temp);
#ifdef DEBUG_THERMOSTAT
DebugPort.print("Conventional thermostat mode: tActual = "); DebugPort.println(u8Temp);
#endif
break;
case 1: // heater controlled thermostat mode - BUT actual temp is tweaked via a changed window
m_TxFrame.setThermostatModeProtocol(1); // using heater thermostat control
u8Temp = (uint8_t)(tActual + 0.5); // use rounded actual unless within window
if(fabs(tDelta) < Window) {
// hold at desired if inside window
u8Temp = NVstore.getDesiredTemperature();
}
else if(fabs(tDelta) <= 1.0) {
// force outside if delta is <= 1 but greater than window
u8Temp = NVstore.getDesiredTemperature() + ((tDelta > 0) ? 1 : -1);
}
m_TxFrame.setTemperature_Actual(u8Temp);
#ifdef DEBUG_THERMOSTAT
DebugPort.print("Heater controlled windowed thermostat mode: tActual = "); DebugPort.println(u8Temp);
#endif
break;
case 2: // BTC controlled thermostat mode
// map linear deviation within thermostat window to a Hz value,
// Hz mode however uses the desired temperature field, somewhere between 8 - 35 for min/max
// so create a desired "temp" according the the current hystersis
tDelta /= Window; // convert tDelta to fraction of window (CAUTION - may be > +-1 !)
#ifdef DEBUG_THERMOSTAT
DebugPort.print("Linear window thermostat mode: Fraction = "); DebugPort.print(tDelta);
#endif
fTemp = (m_TxFrame.getTemperature_Max() + m_TxFrame.getTemperature_Min()) * 0.5; // midpoint - tDelta = 0 hinges here
tDelta *= (m_TxFrame.getTemperature_Max() - fTemp); // linear offset from setpoint
fTemp -= tDelta; // lower Hz when over temp, higher Hz when under!
// bounds limit - recall original tDelta was NOT managed prior!
LOWERLIMIT(fTemp, m_TxFrame.getTemperature_Min());
UPPERLIMIT(fTemp, m_TxFrame.getTemperature_Max());
// apply modifed desired temperature (works in conjunction with thermostatmode = 0!)
u8Temp = (uint8_t)(fTemp + 0.5);
m_TxFrame.setTemperature_Desired(u8Temp);
m_TxFrame.setThermostatModeProtocol(0); // direct heater to use Hz Mode
m_TxFrame.setTemperature_Actual(0); // must force actual to 0 for Hz mode
#ifdef DEBUG_THERMOSTAT
DebugPort.print(" tDesired (pseudo Hz demand) = "); DebugPort.println(u8Temp);
#endif
break;
}
}
else {
m_TxFrame.setThermostatModeProtocol(0); // not using any form of thermostat control
m_TxFrame.setTemperature_Actual(0); // must force actual to 0 for Hz mode
}
// m_TxFrame.setThermostatMode(NVstore.getThermostatMode());
m_TxFrame.Controller.OperatingVoltage = NVstore.getSysVoltage();
m_TxFrame.Controller.FanSensor = NVstore.getFanSensor();
m_TxFrame.Controller.GlowDrive = NVstore.getGlowDrive();
}
else {
m_TxFrame.setPassiveMode(); // this prevents the tuning parameters being saved by heater
}
// ensure CRC valid
m_TxFrame.setCRC();
}
void
CTxManage::Start(unsigned long timenow)
{
if(timenow == 0) // avoid a black hole if millis() has wrapped to zero
timenow++;
m_nStartTime = timenow;
m_bTxPending = true;
}
// generate a Tx Gate, then send the TxFrame to the Blue wire
// Note the serial data is ISR driven, we need to hold off
// for a while to let teh buffewred dat clear before closing the Tx Gate.
bool
CTxManage::CheckTx(unsigned long timenow)
{
if(m_nStartTime) {
long diff = timenow - m_nStartTime;
if(diff > m_nStartDelay) {
// begin front porch of Tx gating pulse
digitalWrite(m_nTxGatePin, HIGH);
}
if(m_bTxPending && (diff > (m_nStartDelay + m_nFrontPorch))) {
// front porch expired, perform serial transmission
// Tx gate remains held high
m_bTxPending = false;
m_BlueWireSerial.write(m_TxFrame.Data, 24); // write native binary values
}
if(diff > (m_nStartDelay + m_nFrameTime)) {
// conclude Tx gating after (emperical) delay
digitalWrite(m_nTxGatePin, LOW);
m_nStartTime = 0; // cancel, we are DONE
}
}
return m_nStartTime == 0; // returns true when done
}

View file

@ -1,72 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
* Copyright (C) 2018 James Clark
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "Protocol.h"
extern void ToggleOnOff();
extern void requestOn();
extern void requestOff();
extern bool reqTempDelta(int delta);
extern bool reqTemp(unsigned char newTemp);
extern bool reqThermoToggle();
extern bool setThermostatMode(unsigned char);
extern bool getThermostatModeActive(); // OEM: actual mode from blue wire, BTC: or our NV
extern void reqPumpPrime(bool on);
float getTemperatureDesired(); // OEM: the advertised value, BTC our setpoint
extern float getTemperatureSensor();
extern int getSetTemp();
extern void setPumpMin(float);
extern void setPumpMax(float);
extern void setFanMin(short);
extern void setFanMax(short);
extern void setFanSensor(unsigned char cVal);
extern void setDateTime(const char* newTime);
extern void setDate(const char* newTime);
extern void setTime(const char* newTime);
extern void setGlowDrive(unsigned char val);
extern void saveNV();
extern void setSystemVoltage(float val);
extern const CProtocolPackage& getHeaterInfo();
extern void interpretJsonCommand(char* pLine);
extern void resetWebModerator();
extern void resetJSONmoderator();
extern const char* getBlueWireStatStr();
extern bool hasOEMcontroller();
extern bool hasOEMLCDcontroller();
extern int getBlueWireStat();
extern int getSmartError();
extern bool isCyclicActive();
extern float getVersion();
const char* getVersionStr();
extern const char* getVersionDate();
extern int getBoardRevision();
extern void setupGPIO();
extern void setGPIO(int channel, bool state);
extern bool getGPIO(int channel);
#define LOWERLIMIT(A, B) if((A) < (B)) (A) = (B)
#define UPPERLIMIT(A, B) if((A) > (B)) (A) = (B)
#define ROLLUPPERLIMIT(A, B, C) if((A) > (B)) (A) = (C)
#define ROLLLOWERLIMIT(A, B, C) if((A) < (B)) (A) = (C)

View file

@ -1,332 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "BTC_JSON.h"
#include "DebugPort.h"
#include "../Protocol/helpers.h"
#include "NVstorage.h"
#include "../RTC/BTCDateTime.h"
#include "../RTC/Timers.h"
#include "../RTC/TimerManager.h"
#include "../Bluetooth/BluetoothAbstract.h"
#include "../WiFi/BTCWebServer.h"
#include "../cfg/BTCConfig.h"
char defaultJSONstr[64];
CModerator JSONmoderator;
CTimerModerator TimerModerator;
int timerConflict = 0;
void validateTimer(int ID);
void interpretJsonCommand(char* pLine)
{
if(strlen(pLine) == 0)
return;
DebugPort.print("JSON parse... "); DebugPort.print(pLine);
/* for(int i=0; i<strlen(pLine); i++) {
char msg[8];
sprintf(msg, "%02X ", pLine[i]);
DebugPort.print(msg);
}*/
StaticJsonBuffer<512> jsonBuffer; // create a JSON buffer on the heap
JsonObject& obj = jsonBuffer.parseObject(pLine);
if(!obj.success()) {
DebugPort.println(" FAILED");
return;
}
DebugPort.println(" OK");
JsonObject::iterator it;
for(it = obj.begin(); it != obj.end(); ++it) {
if(strcmp("TempDesired", it->key) == 0) {
if(!reqTemp(it->value.as<unsigned char>())) { // this request is blocked if OEM controller active
JSONmoderator.reset("TempDesired");
}
}
else if(strcmp("RunState", it->key) == 0) {
if(it->value.as<unsigned char>()) {
requestOn();
}
else {
requestOff();
}
}
else if(strcmp("PumpMin", it->key) == 0) {
setPumpMin(it->value.as<float>());
}
else if(strcmp("PumpMax", it->key) == 0) {
setPumpMax(it->value.as<float>());
}
else if(strcmp("FanMin", it->key) == 0) {
setFanMin(it->value.as<short>());
}
else if(strcmp("FanMax", it->key) == 0) {
setFanMax(it->value.as<short>());
}
else if(strcmp("ThermostatOvertemp", it->key) == 0) {
sCyclicThermostat cyclic = NVstore.getCyclicMode();
cyclic.Stop = it->value.as<char>();
NVstore.setCyclicMode(cyclic);
}
else if(strcmp("ThermostatUndertemp", it->key) == 0) {
sCyclicThermostat cyclic = NVstore.getCyclicMode();
cyclic.Start = it->value.as<char>();
NVstore.setCyclicMode(cyclic);
}
else if(strcmp("ThermostatMethod", it->key) == 0) {
NVstore.setThermostatMethodMode(it->value.as<unsigned char>());
}
else if(strcmp("ThermostatWindow", it->key) == 0) {
NVstore.setThermostatMethodWindow(it->value.as<float>());
}
else if(strcmp("Thermostat", it->key) == 0) {
if(!setThermostatMode(it->value.as<unsigned char>())) { // this request is blocked if OEM controller active
JSONmoderator.reset("ThermoStat");
}
}
else if(strcmp("NVsave", it->key) == 0) {
if(it->value.as<int>() == 8861)
saveNV();
}
else if(strcmp("DateTime", it->key) == 0) {
setDateTime(it->value.as<const char*>());
}
else if(strcmp("Date", it->key) == 0) {
setDate(it->value.as<const char*>());
}
else if(strcmp("Time", it->key) == 0) {
setTime(it->value.as<const char*>());
}
else if(strcmp("PumpPrime", it->key) == 0) {
reqPumpPrime(it->value.as<unsigned char>());
}
else if(strcmp("Refresh", it->key) == 0) {
resetJSONmoderator();
}
else if(strcmp("SystemVoltage", it->key) == 0) {
setSystemVoltage(it->value.as<float>());
}
else if(strcmp("TimerDays", it->key) == 0) {
// value encoded as "ID Days,Days"
decodeJSONTimerDays(it->value.as<const char*>());
}
else if(strcmp("TimerStart", it->key) == 0) {
// value encoded as "ID HH:MM"
decodeJSONTimerTime(0, it->value.as<const char*>());
}
else if(strcmp("TimerStop", it->key) == 0) {
// value encoded as "ID HH:MM"
decodeJSONTimerTime(1, it->value.as<const char*>());
}
else if(strcmp("TimerRepeat", it->key) == 0) {
// value encoded as "ID val"
decodeJSONTimerNumeric(0, it->value.as<const char*>());
}
else if(strcmp("TimerTemp", it->key) == 0) {
decodeJSONTimerNumeric(1, it->value.as<const char*>());
}
else if(strcmp("TimerConflict", it->key) == 0) {
validateTimer(it->value.as<int>());
}
else if(strcmp("TimerRefresh", it->key) == 0) {
TimerModerator.reset();
}
else if(strcmp("FanSensor", it->key) == 0) {
setFanSensor(it->value.as<unsigned char>());
}
}
}
void validateTimer(int ID)
{
ID--; // supplied as +1
if(!(ID >= 0 && ID < 14))
return;
timerConflict = CTimerManager::conflictTest(ID); // check targeted timer against other timers
TimerModerator.reset(ID); // ensure we update client with our (real) version of the selected timer
}
bool makeJSONString(CModerator& moderator, char* opStr, int len)
{
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
bool bSend = false; // reset should send flag
float tidyTemp = getTemperatureSensor();
tidyTemp = int(tidyTemp * 10) * 0.1f; // round to 0.1 resolution
if(tidyTemp > -80) {
bSend |= moderator.addJson("TempCurrent", tidyTemp, root);
}
bSend |= moderator.addJson("TempDesired", getTemperatureDesired(), root);
bSend |= moderator.addJson("TempMin", getHeaterInfo().getTemperature_Min(), root);
bSend |= moderator.addJson("TempMax", getHeaterInfo().getTemperature_Max(), root);
bSend |= moderator.addJson("TempBody", getHeaterInfo().getTemperature_HeatExchg(), root);
// bSend |= moderator.addJson("RunState", getHeaterInfo().getRunState(), root);
bSend |= moderator.addJson("RunState", getHeaterInfo().getRunStateEx(), root);
bSend |= moderator.addJson("RunString", getHeaterInfo().getRunStateStr(), root); // verbose it up!
bSend |= moderator.addJson("ErrorState", getHeaterInfo().getErrState(), root );
bSend |= moderator.addJson("ErrorString", getHeaterInfo().getErrStateStrEx(), root); // verbose it up!
bSend |= moderator.addJson("Thermostat", getThermostatModeActive(), root );
bSend |= moderator.addJson("PumpFixed", getHeaterInfo().getPump_Fixed(), root );
bSend |= moderator.addJson("PumpMin", getHeaterInfo().getPump_Min(), root );
bSend |= moderator.addJson("PumpMax", getHeaterInfo().getPump_Max(), root );
bSend |= moderator.addJson("PumpActual", getHeaterInfo().getPump_Actual(), root );
bSend |= moderator.addJson("FanMin", getHeaterInfo().getFan_Min(), root );
bSend |= moderator.addJson("FanMax", getHeaterInfo().getFan_Max(), root );
bSend |= moderator.addJson("FanRPM", getHeaterInfo().getFan_Actual(), root );
bSend |= moderator.addJson("FanVoltage", getHeaterInfo().getFan_Voltage(), root );
bSend |= moderator.addJson("FanSensor", getHeaterInfo().getFan_Sensor(), root );
bSend |= moderator.addJson("InputVoltage", getHeaterInfo().getBattVoltage(), root );
bSend |= moderator.addJson("SystemVoltage", getHeaterInfo().getSystemVoltage(), root );
bSend |= moderator.addJson("GlowVoltage", getHeaterInfo().getGlow_Voltage(), root );
bSend |= moderator.addJson("GlowCurrent", getHeaterInfo().getGlow_Current(), root );
bSend |= moderator.addJson("BluewireStat", getBlueWireStatStr(), root );
bSend |= moderator.addJson("TempMode", NVstore.getDegFMode(), root);
if(bSend) {
root.printTo(opStr, len);
}
return bSend;
}
bool makeJSONStringEx(CModerator& moderator, char* opStr, int len)
{
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
bool bSend = false; // reset should send flag
bSend |= moderator.addJson("ThermostatMethod", NVstore.getThermostatMethodMode(), root);
bSend |= moderator.addJson("ThermostatWindow", NVstore.getThermostatMethodWindow(), root);
bSend |= moderator.addJson("ThermostatOvertemp", NVstore.getCyclicMode().Stop, root);
bSend |= moderator.addJson("ThermostatUndertemp", NVstore.getCyclicMode().Start, root);
if(bSend) {
root.printTo(opStr, len);
}
return bSend;
}
// the way the JSON timer strings are crafted, we have to iterate over each timer's parameters
// individually, the JSON name is always the same for each timer, the payload IDs the specific
// timer
// Only timer parameters that have changed will be sent, after reset the typical string will be
// {"TimerStart":XX:XX,"TimerStop":XX:XX,"TimerDays":XX,"TimerRepeat":X}
bool makeJSONTimerString(int channel, char* opStr, int len)
{
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
bool bSend = false; // reset should send flag
sTimer timerInfo;
NVstore.getTimerInfo(channel, timerInfo);
bSend |= TimerModerator.addJson(channel, timerInfo, root );
if(bSend) {
root.printTo(opStr, len);
}
return bSend;
}
void updateJSONclients(bool report)
{
// update general parameters
char jsonStr[800];
{
if(makeJSONString(JSONmoderator, jsonStr, sizeof(jsonStr))) {
if (report) {
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
}
sendWebServerString( jsonStr );
getBluetoothClient().send( jsonStr );
}
}
// update extended params
{
if(makeJSONStringEx(JSONmoderator, jsonStr, sizeof(jsonStr))) {
if (report) {
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
}
sendWebServerString( jsonStr );
getBluetoothClient().send( jsonStr );
}
}
// update timer parameters
bool bNewTimerInfo = false;
for(int tmr=0; tmr<14; tmr++)
{
unsigned long tStart = millis();
if(makeJSONTimerString(tmr, jsonStr, sizeof(jsonStr))) {
unsigned long tJSON = millis() - tStart;
if (report) {
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
}
tStart = millis();
sendWebServerString( jsonStr );
unsigned long tWF = millis() - tStart;
tStart = millis();
getBluetoothClient().send( jsonStr );
unsigned long tBT = millis() - tStart;
bNewTimerInfo = true;
DebugPort.print("JSON times : "); DebugPort.print(tJSON); DebugPort.print(",");DebugPort.print(tBT); DebugPort.print(",");DebugPort.println(tWF);
}
}
// request timer refesh upon clients
if(bNewTimerInfo) {
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
if(timerConflict) {
root.set("TimerConflict", timerConflict);
timerConflict = 0;
}
root.set("TimerRefresh", 1);
root.printTo(jsonStr, 800);
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
sendWebServerString( jsonStr );
getBluetoothClient().send( jsonStr );
}
}
void resetJSONmoderator()
{
JSONmoderator.reset();
TimerModerator.reset();
}

View file

@ -1,374 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "GPIO.h"
#include "../Protocol/helpers.h"
#include <driver/adc.h>
#include "DebugPort.h"
const int BREATHINTERVAL = 45;
const int FADEAMOUNT = 3;
const int FLASHPERIOD = 2000;
const int ONFLASHINTERVAL = 50;
CGPIOin::CGPIOin()
{
_Mode = GPIOinNone;
_lastKey = 0;
}
void
CGPIOin::begin(int pin1, int pin2, GPIOinModes mode, int activeState)
{
_Debounce.addPin(pin1);
_Debounce.addPin(pin2);
_Debounce.setActiveState(activeState);
setMode(mode);
}
uint8_t
CGPIOin::getState(int channel)
{
int mask = 0x01 << (channel & 0x01);
return (_Debounce.getState() & mask) != 0;
}
void
CGPIOin::manage()
{
switch (_Mode) {
case GPIOinNone:
break;
case GPIOinOn1Off2:
_doOn1Off2();
break;
case GPIOinOnHold1:
_doOnHold1();
break;
case GPIOinOn1Off1:
_doOn1Off1();
break;
}
}
void
CGPIOin::_doOn1Off2()
{
uint8_t newKey = _Debounce.manage();
// determine edge events
uint8_t keyChange = newKey ^ _lastKey;
_lastKey = newKey;
if(keyChange) {
if(newKey & 0x01) {
requestOn();
}
if(newKey & 0x02) {
requestOff();
}
}
}
// mode where heater runs if input 1 is shorted
// stops when open
void
CGPIOin::_doOnHold1()
{
uint8_t newKey = _Debounce.manage();
// determine edge events
uint8_t keyChange = newKey ^ _lastKey;
_lastKey = newKey;
if(keyChange) {
if(newKey & 0x01) {
requestOn();
}
else {
requestOff();
}
}
}
// mode where heater runs if input 1 is shorted
// stops when open
void
CGPIOin::_doOn1Off1()
{
uint8_t newKey = _Debounce.manage();
// determine edge events
uint8_t keyChange = newKey ^ _lastKey;
_lastKey = newKey;
if(keyChange) {
if(newKey & 0x01) {
if(getHeaterInfo().getRunStateEx())
requestOff();
else
requestOn();
}
}
}
CGPIOout::CGPIOout()
{
_Mode = GPIOoutNone;
_pins[0] = 0;
_pins[1] = 0;
_breatheDelay = 0;
_statusState = 0;
_statusDelay = 0;
_userState = 0;
_prevState = -1;
}
void
CGPIOout::begin(int pin1, int pin2, GPIOoutModes mode)
{
_pins[0] = pin1;
_pins[1] = pin2;
if(pin1) {
pinMode(pin1, OUTPUT); // GPIO output pin #1
digitalWrite(pin1, LOW);
ledcSetup(0, 500, 8); // create PWM channel for GPIO1: 500Hz, 8 bits
}
if(pin2) {
pinMode(pin2, OUTPUT); // GPIO output pin #2
digitalWrite(pin2, LOW);
ledcSetup(1, 500, 8); // create PWM channel for GPIO2: 500Hz, 8 bits
}
setMode(mode);
}
void
CGPIOout::setMode(GPIOoutModes mode)
{
_Mode = mode;
_prevState = -1;
ledcDetachPin(_pins[0]); // ensure PWM detached from IO line
ledcDetachPin(_pins[1]); // ensure PWM detached from IO line
};
void
CGPIOout::manage()
{
switch (_Mode) {
case GPIOoutNone: break;
case GPIOoutStatus: _doStatus(); break;
case GPIOoutUser: _doUser(); break;
}
}
void
CGPIOout::_doStatus()
{
if(_pins[0] == 0)
return;
// DebugPort.println("GPIOout::_doStatus()");
int runstate = getHeaterInfo().getRunStateEx();
int statusMode = 0;
switch(runstate) {
case 1:
case 2:
case 3:
case 4:
case 9:
// starting modes
statusMode = 1;
break;
case 5:
// run mode
statusMode = 2;
break;
case 6:
case 7:
case 8:
case 11:
case 12:
// cooldown modes
statusMode = 3;
break;
case 10:
// suspend mode
statusMode = 4;
break;
}
// change of mode typically requires changing from simple digital out
// to PWM or vice versa
if(_prevState != statusMode) {
_prevState = statusMode;
_statusState = 0;
_statusDelay = millis() + BREATHINTERVAL;
switch(statusMode) {
case 0:
ledcDetachPin(_pins[0]); // detach PWM from IO line
digitalWrite(_pins[0], LOW);
break;
case 1:
ledcAttachPin(_pins[0], 0); // attach PWM to GPIO line
ledcWrite(0, _statusState);
_breatheDelay = millis() + BREATHINTERVAL;
break;
case 2:
ledcDetachPin(_pins[0]); // detach PWM from IO line
digitalWrite(_pins[0], HIGH);
break;
case 3:
ledcAttachPin(_pins[0], 0); // attach PWM to GPIO line
_statusState = 255;
ledcWrite(0, _statusState);
_breatheDelay = millis() + BREATHINTERVAL;
break;
case 4:
ledcDetachPin(_pins[0]); // detach PWM from IO line
_breatheDelay += (FLASHPERIOD - ONFLASHINTERVAL); // extended off
digitalWrite(_pins[0], LOW);
break;
}
}
switch(statusMode) {
case 1: _doStartMode(); break;
case 3: _doStopMode(); break;
case 4: _doSuspendMode(); break;
}
}
void
CGPIOout::_doUser()
{
// DebugPort.println("GPIOout::_doUser()");
if(_pins[0]) {
digitalWrite(_pins[0], (_userState & 0x01) ? HIGH : LOW);
}
if(_pins[1]) {
digitalWrite(_pins[1], (_userState & 0x02) ? HIGH : LOW);
}
}
void
CGPIOout::_doStartMode() // breath up PWM
{
long tDelta = millis() - _breatheDelay;
if(tDelta >= 0) {
_breatheDelay += BREATHINTERVAL;
int expo = ((_statusState >> 5) + 1);
_statusState += expo;
_statusState &= 0xff;
ledcWrite(0, _statusState);
}
}
void
CGPIOout::_doStopMode() // breath down PWM
{
long tDelta = millis() - _breatheDelay;
if(tDelta >= 0) {
_breatheDelay += BREATHINTERVAL;
int expo = ((_statusState >> 5) + 1);
_statusState -= expo;
_statusState &= 0xff;
ledcWrite(0, _statusState);
}
}
void
CGPIOout::_doSuspendMode() // brief flash
{
long tDelta = millis() - _breatheDelay;
if(tDelta >= 0) {
_statusState++;
if(_statusState & 0x01) {
_breatheDelay += ONFLASHINTERVAL; // brief flash on
digitalWrite(_pins[0], HIGH);
}
else {
_breatheDelay += (FLASHPERIOD - ONFLASHINTERVAL); // extended off
digitalWrite(_pins[0], LOW);
}
}
}
void
CGPIOout::setState(int channel, bool state)
{
int mask = 0x01 << (channel & 0x01);
if(state)
_userState |= mask;
else
_userState &= ~mask;
}
bool
CGPIOout::getState(int channel)
{
int mask = 0x01 << (channel & 0x01);
return (_userState & mask) != 0;
}
// expected external analogue circuit is a 10k pot.
// Top end of pot is connected to GPIO Vcc (red wire) via 5k6 fixed resistor. (GPIO Vcc is 5V via schottky diode)
// Bottom end of pot is connected to GND (black wire) via 1k fixed resistor.
// Wiper is into Pin 6 of GPIO (white wire) - analogue input
CGPIOalg::CGPIOalg()
{
_expMean = 0;
}
void
CGPIOalg::begin(adc1_channel_t pin, GPIOalgModes mode)
{
_pin = pin;
_Mode = mode;
if(_Mode != GPIOalgNone) {
adc_gpio_init(ADC_UNIT_1, ADC_CHANNEL_5);
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC1_CHANNEL_5, ADC_ATTEN_11db);
}
}
void CGPIOalg::manage()
{
const float fAlpha = 0.95; // exponential mean alpha
if(_Mode != GPIOalgNone) {
int read_raw;
char msg[32];
read_raw = adc1_get_raw( ADC1_CHANNEL_5);
sprintf(msg, "ADC: %d", read_raw );
_expMean = _expMean * fAlpha + (1-fAlpha) * float(read_raw);
// DebugPort.println(msg);
}
}
int
CGPIOalg::getValue()
{
return _expMean;
}

View file

@ -1,104 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __BTCGPIO_H__
#define __BTCGPIO_H__
#include <stdint.h>
#include <driver/adc.h>
#include "Debounce.h"
enum GPIOinModes {
GPIOinNone,
GPIOinOn1Off2, // input 1 closure, heater starts; input2 closure, heater stops
GPIOinOnHold1, // hold input 1 closure, heater runs; input 1 open, heater stops
GPIOinOn1Off1 // alternate input 1 closures start or stop the heater
};
enum GPIOoutModes {
GPIOoutNone,
GPIOoutStatus,
GPIOoutUser
};
enum GPIOalgModes {
GPIOalgNone, // Unmodified V2.0 PCBs must use this - ADC2 / Wifi unresolvable conflict
GPIOalgHeatDemand,
};
class CGPIOin {
GPIOinModes _Mode;
CDebounce _Debounce;
// int _pinActive;
// int _pins[2];
// uint8_t _prevPins;
// uint8_t _debouncedPins;
uint8_t _lastKey;
// unsigned long _lastDebounceTime;
// unsigned long _debounceDelay;
// uint8_t _scanInputs();
void _doOn1Off2();
void _doOnHold1();
void _doOn1Off1();
public:
CGPIOin();
void setMode(GPIOinModes mode) { _Mode = mode; };
void begin(int pin1, int pin2, GPIOinModes mode, int activeState);
void manage();
uint8_t getState(int channel);
};
class CGPIOout {
GPIOoutModes _Mode;
void _doStatus();
void _doUser();
int _pins[2];
int _prevState;
int _statusState;
int _statusDelay;
unsigned long _breatheDelay;
uint8_t _userState;
void _doStartMode();
void _doStopMode();
void _doSuspendMode();
public:
CGPIOout();
void setMode(GPIOoutModes mode);
void begin(int pin1, int pin2, GPIOoutModes mode);
void manage();
void setState(int channel, bool state);
bool getState(int channel);
};
class CGPIOalg {
GPIOalgModes _Mode;
float _expMean;
adc1_channel_t _pin;
public:
CGPIOalg();
void begin(adc1_channel_t pin, GPIOalgModes mode);
void manage();
int getValue();
};
#endif // __BTCGPIO_H__

View file

@ -1,155 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __BTC_MODERATOR_H__
#define __BTC_MODERATOR_H__
#include <map>
#include <ArduinoJSON.h>
#include "../RTC/Timers.h"
#include "DebugPort.h"
class CTimerModerator {
sTimer Memory[14];
enum eType { eStart, eStop, eDays, eRpt, eTemp};
const char* _getName(eType type);
int _shouldSend(int channel, const sTimer& toSend);
public:
CTimerModerator();
bool addJson(int channel, const sTimer& toSend, JsonObject& root);
void reset();
void reset(int channel);
};
template <class T>
class TModerator {
std::map<const char*, T> Memory;
public:
bool shouldSend(const char* name, T value);
bool addJson(const char* name, T value, JsonObject& root);
void reset();
void reset(const char* name);
};
template<class T>
bool TModerator<T>::shouldSend(const char* name, T value)
{
bool retval = true;
auto it = Memory.find(name);
if(it != Memory.end()) {
retval = it->second != value;
it->second = value;
}
else {
Memory[name] = value;
}
return retval;
}
template<class T>
bool TModerator<T>::addJson(const char* name, T value, JsonObject& root)
{
bool retval;
if( retval = shouldSend(name, value ) )
root.set(name, value);
return retval;
}
template<class T>
void TModerator<T>::reset()
{
for(auto it = Memory.begin(); it != Memory.end(); ++it) {
if(std::is_pointer<T>::value) {
it->second = NULL;
}
else {
it->second = it->second+100;
}
}
}
template<class T>
void TModerator<T>::reset(const char* name)
{
auto it = Memory.find(name);
if(it != Memory.end()) {
DebugPort.print("Resetting moderator: \""); DebugPort.print(name); DebugPort.println("\"");
if(std::is_pointer<T>::value) {
it->second = NULL;
}
else {
it->second = it->second+100;
}
}
}
class CModerator {
TModerator<int> iModerator;
TModerator<float> fModerator;
TModerator<unsigned char> ucModerator;
TModerator<const char*> szModerator;
public:
// integer values
bool shouldSend(const char* name, int value) {
return iModerator.shouldSend(name, value);
};
bool addJson(const char* name, int value, JsonObject& root) {
return iModerator.addJson(name, value, root);
};
// float values
bool shouldSend(const char* name, float value) {
return fModerator.shouldSend(name, value);
};
bool addJson(const char* name, float value, JsonObject& root) {
return fModerator.addJson(name, value, root);
};
// unsigned char values
bool shouldSend(const char* name, unsigned char value) {
return ucModerator.shouldSend(name, value);
};
bool addJson(const char* name, unsigned char value, JsonObject& root) {
return ucModerator.addJson(name, value, root);
};
// const char* values
bool shouldSend(const char* name, const char* value) {
return szModerator.shouldSend(name, value);
};
bool addJson(const char* name, const char* value, JsonObject& root) {
return szModerator.addJson(name, value, root);
};
// force changes on all held values
void reset() {
iModerator.reset();
fModerator.reset();
ucModerator.reset();
szModerator.reset();
};
void reset(const char* name) {
iModerator.reset(name);
fModerator.reset(name);
ucModerator.reset(name);
szModerator.reset(name);
};
};
#endif // __BTC_MODERATOR_H__

View file

@ -1,634 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include <Arduino.h>
#include "NVStorage.h"
#include "DebugPort.h"
#include <driver/adc.h>
bool u8inBounds(uint8_t test, uint8_t minLim, uint8_t maxLim);
bool s8inBounds(int8_t test, int8_t minLim, int8_t maxLim);
bool u8Match2(uint8_t test, uint8_t test1, uint8_t test2);
bool u16inBounds(uint16_t test, uint16_t minLim, uint16_t maxLim);
bool s32inBounds(long test, long minLim, long maxLim);
bool thermoMethodinBounds(uint8_t test, uint8_t minLim, uint8_t maxLim);
bool
sNVStore::valid()
{
bool retval = true;
retval &= Options.valid();
for(int i=0; i<2; i++) {
retval &= timer[i].valid();
}
retval &= Heater.valid();
return retval;
}
void
sNVStore::init()
{
for(int i=0; i<2; i++) {
timer[i].init();
}
Options.init();
Heater.init();
}
CHeaterStorage::CHeaterStorage()
{
_calValues.Heater.init();
}
float
CHeaterStorage::getPmin()
{
return float(_calValues.Heater.Pmin) * 0.1f;
}
float
CHeaterStorage::getPmax()
{
return float(_calValues.Heater.Pmax) * 0.1f;
}
unsigned short
CHeaterStorage::getFmin()
{
return _calValues.Heater.Fmin;
}
unsigned short
CHeaterStorage::getFmax()
{
return _calValues.Heater.Fmax;
}
unsigned char
CHeaterStorage::getDesiredTemperature()
{
return _calValues.Heater.setTemperature;
}
unsigned char
CHeaterStorage::getThermostatMode()
{
return _calValues.Heater.ThermostatMode;
}
unsigned char
CHeaterStorage::getThermostatMethodMode()
{
return _calValues.Options.ThermostatMethod & 0x03;
}
float
CHeaterStorage::getThermostatMethodWindow()
{
return float((_calValues.Options.ThermostatMethod >> 2) & 0x3f) * 0.1f; // top 5 bits / 10, then / 2
}
void
CHeaterStorage::setPmin(float val)
{
uint8_t cVal = (uint8_t)(val * 10.f + 0.5f);
_calValues.Heater.Pmin = cVal;
}
void
CHeaterStorage::setPmax(float val)
{
uint8_t cVal = (uint8_t)(val * 10.f + 0.5f);
_calValues.Heater.Pmax = cVal;
}
void
CHeaterStorage::setFmin(unsigned short val)
{
_calValues.Heater.Fmin = val;
}
void
CHeaterStorage::setFmax(unsigned short val)
{
_calValues.Heater.Fmax = val;
}
void
CHeaterStorage::setDesiredTemperature(unsigned char val)
{
_calValues.Heater.setTemperature = val;
}
void
CHeaterStorage::setThermostatMode(unsigned char val)
{
_calValues.Heater.ThermostatMode = val;
}
void
CHeaterStorage::setThermostatMethodMode(unsigned char val)
{
_calValues.Options.ThermostatMethod &= ~0x03;
_calValues.Options.ThermostatMethod |= (val & 0x03);
}
void
CHeaterStorage::setThermostatMethodWindow(float val)
{
_calValues.Options.ThermostatMethod &= 0x03;
int nVal = int(val * 10 + 0.5);
_calValues.Options.ThermostatMethod |= ((nVal & 0x3F) << 2);
}
void
CHeaterStorage::setSystemVoltage(float fVal)
{
int val = int(fVal * 10.0);
if(val == 120 || val == 240) {
_calValues.Heater.sysVoltage = val;
}
}
unsigned char
CHeaterStorage::getSysVoltage()
{
return _calValues.Heater.sysVoltage;
}
void
CHeaterStorage::setFanSensor(unsigned char val)
{
if(val == 2)
_calValues.Heater.fanSensor = 2;
else
_calValues.Heater.fanSensor = 1;
}
unsigned char
CHeaterStorage::getFanSensor()
{
return _calValues.Heater.fanSensor;
}
void
CHeaterStorage::setGlowDrive(unsigned char val)
{
if(val >=1 && val <= 6)
_calValues.Heater.glowDrive = val;
else
_calValues.Heater.glowDrive = 5;
}
unsigned char
CHeaterStorage::getGlowDrive()
{
return _calValues.Heater.glowDrive;
}
void
CHeaterStorage::getTimerInfo(int idx, sTimer& timerInfo)
{
if(idx >= 0 && idx < 14) {
timerInfo = _calValues.timer[idx];
}
}
void
CHeaterStorage::setTimerInfo(int idx, const sTimer& timerInfo)
{
if(idx >= 0 && idx < 14) {
_calValues.timer[idx] = timerInfo;
}
}
long
CHeaterStorage::getDimTime()
{
return _calValues.Options.dimTime;
}
void
CHeaterStorage::setDimTime(long val)
{
_calValues.Options.dimTime = val;
}
long
CHeaterStorage::getMenuTimeout()
{
return _calValues.Options.menuTimeout;
}
void
CHeaterStorage::setMenuTimeout(long val)
{
_calValues.Options.menuTimeout = val;
}
unsigned char
CHeaterStorage::getDegFMode()
{
return _calValues.Options.degF;
}
void
CHeaterStorage::setDegFMode(unsigned char val)
{
_calValues.Options.degF = val;
save();
}
unsigned char
CHeaterStorage::getWifiEnabled()
{
return _calValues.Options.enableWifi;
}
void
CHeaterStorage::setWifiEnabled(unsigned char val)
{
_calValues.Options.enableWifi = val;
save();
}
unsigned char
CHeaterStorage::getOTAEnabled()
{
return _calValues.Options.enableOTA;
}
void
CHeaterStorage::setOTAEnabled(unsigned char val)
{
_calValues.Options.enableOTA = val;
save();
}
const sCyclicThermostat&
CHeaterStorage::getCyclicMode() const
{
return _calValues.Options.cyclic;
}
void
CHeaterStorage::setCyclicMode(const sCyclicThermostat& val)
{
_calValues.Options.cyclic = val;
save();
}
GPIOinModes
CHeaterStorage::getGPIOinMode()
{
GPIOinModes inMode = GPIOinNone;
switch(_calValues.Options.GPIOinMode) {
case 0: inMode = GPIOinNone; break;
case 1: inMode = GPIOinOn1Off2; break;
case 2: inMode = GPIOinOnHold1; break;
case 3: inMode = GPIOinOn1Off1; break;
}
return inMode;
}
void
CHeaterStorage::setGPIOinMode(unsigned char val)
{
_calValues.Options.GPIOinMode = val;
}
GPIOoutModes
CHeaterStorage::getGPIOoutMode()
{
GPIOoutModes outMode = GPIOoutNone;
switch(_calValues.Options.GPIOoutMode) {
case 0: outMode = GPIOoutNone; break;
case 1: outMode = GPIOoutStatus; break;
case 2: outMode = GPIOoutUser; break;
}
return outMode;
}
void
CHeaterStorage::setGPIOoutMode(unsigned char val)
{
_calValues.Options.GPIOoutMode = val;
}
GPIOalgModes
CHeaterStorage::getGPIOalgMode()
{
GPIOalgModes algMode = GPIOalgNone;
switch (_calValues.Options.GPIOalgMode) {
case 0: algMode = GPIOalgNone; break;
case 1: algMode = GPIOalgHeatDemand; break;
}
return algMode;
}
void
CHeaterStorage::setGPIOalgMode(unsigned char val)
{
_calValues.Options.GPIOalgMode = val;
}
uint16_t
CHeaterStorage::getFrameRate()
{
return _calValues.Options.FrameRate;
}
void
CHeaterStorage::setFrameRate(uint16_t val)
{
_calValues.Options.FrameRate = val;
}
const sHomeMenuActions&
CHeaterStorage::getHomeMenu() const
{
return _calValues.Options.HomeMenu;
}
void
CHeaterStorage::setHomeMenu(sHomeMenuActions val)
{
_calValues.Options.HomeMenu = val;
}
///////////////////////////////////////////////////////////////////////////////////////
// ESP32
//
//#ifdef ESP32
CESP32HeaterStorage::CESP32HeaterStorage()
{
}
CESP32HeaterStorage::~CESP32HeaterStorage()
{
}
void
CESP32HeaterStorage::init()
{
}
void
CESP32HeaterStorage::load()
{
DebugPort.println("Reading from NV storage");
loadHeater();
for(int i=0; i<14; i++) {
loadTimer(i);
}
loadUI();
}
void
CESP32HeaterStorage::save()
{
DebugPort.println("Saving to NV storage");
saveHeater();
for(int i=0; i<14; i++) {
saveTimer(i);
}
saveUI();
}
// **** MAX LENGTH is 15 for name and values ****
void
CESP32HeaterStorage::loadHeater()
{
// section for heater calibration params
preferences.begin("Calibration", false);
validatedLoad("minPump", _calValues.Heater.Pmin, 14, u8inBounds, 4, 100);
validatedLoad("maxPump", _calValues.Heater.Pmax, 45, u8inBounds, 4, 150);
validatedLoad("minFan", _calValues.Heater.Fmin, 1500, u16inBounds, 100, 5000);
validatedLoad("maxFan", _calValues.Heater.Fmax, 4500, u16inBounds, 100, 6000);
validatedLoad("thermostat", _calValues.Heater.ThermostatMode, 1, u8inBounds, 0, 1);
validatedLoad("setTemperature", _calValues.Heater.setTemperature, 22, u8inBounds, 0, 40);
validatedLoad("systemVoltage", _calValues.Heater.sysVoltage, 120, u8Match2, 120, 240);
validatedLoad("fanSensor", _calValues.Heater.fanSensor, 1, u8inBounds, 1, 2);
validatedLoad("glowDrive", _calValues.Heater.glowDrive, 5, u8inBounds, 1, 6);
preferences.end();
}
// **** MAX LENGTH is 15 for name and values ****
void
CESP32HeaterStorage::saveHeater()
{
// section for heater calibration params
preferences.begin("Calibration", false);
preferences.putUChar("minPump", _calValues.Heater.Pmin);
preferences.putUChar("maxPump", _calValues.Heater.Pmax);
preferences.putUShort("minFan", _calValues.Heater.Fmin);
preferences.putUShort("maxFan", _calValues.Heater.Fmax);
preferences.putUChar("thermostat", _calValues.Heater.ThermostatMode);
preferences.putUChar("setTemperature", _calValues.Heater.setTemperature);
preferences.putUChar("systemVoltage", _calValues.Heater.sysVoltage);
preferences.putUChar("fanSensor", _calValues.Heater.fanSensor);
preferences.putUChar("glowDrive", _calValues.Heater.glowDrive);
preferences.end();
}
// **** MAX LENGTH is 15 for name and values ****
void
CESP32HeaterStorage::loadTimer(int idx)
{
sTimer& timer = _calValues.timer[idx];
timer.timerID = idx;
char SectionName[16];
sprintf(SectionName, "timer%d", idx+1);
preferences.begin(SectionName, false);
validatedLoad("startHour", timer.start.hour, 0, s8inBounds, 0, 23);
validatedLoad("startMin", timer.start.min, 0, s8inBounds, 0, 59);
validatedLoad("stopHour", timer.stop.hour, 0, s8inBounds, 0, 23);
validatedLoad("stopMin", timer.stop.min, 0, s8inBounds, 0, 59);
validatedLoad("enabled", timer.enabled, 0, u8inBounds, 0, 255); // all 8 bits used!
validatedLoad("repeat", timer.repeat, 0, u8inBounds, 0, 1);
validatedLoad("temperature", timer.temperature, 22, u8inBounds, 8, 35);
preferences.end();
}
// **** MAX LENGTH is 15 for name and values ****
void
CESP32HeaterStorage::saveTimer(int idx)
{
sTimer& timer = _calValues.timer[idx];
char SectionName[16];
sprintf(SectionName, "timer%d", idx+1);
preferences.begin(SectionName, false);
preferences.putChar("startHour", timer.start.hour);
preferences.putChar("startMin", timer.start.min);
preferences.putChar("stopHour", timer.stop.hour);
preferences.putChar("stopMin", timer.stop.min);
preferences.putUChar("enabled", timer.enabled);
preferences.putUChar("repeat", timer.repeat);
preferences.putUChar("temperature", timer.temperature);
preferences.end();
}
// **** MAX LENGTH is 15 for name and values ****
void
CESP32HeaterStorage::loadUI()
{
preferences.begin("user", false);
validatedLoad("dimTime", _calValues.Options.dimTime, 60000, s32inBounds, -600000, 600000);
validatedLoad("menuTimeout", _calValues.Options.menuTimeout, 60000, s32inBounds, 0, 300000);
validatedLoad("degF", _calValues.Options.degF, 0, u8inBounds, 0, 1);
validatedLoad("thermoMethod", _calValues.Options.ThermostatMethod, (10 << 2), u8inBounds, 0, 2, 0x03);
validatedLoad("enableWifi", _calValues.Options.enableWifi, 1, u8inBounds, 0, 1);
validatedLoad("enableOTA", _calValues.Options.enableOTA, 1, u8inBounds, 0, 1);
validatedLoad("cyclicStop", _calValues.Options.cyclic.Stop, 0, s8inBounds, 0, 10);
validatedLoad("cyclicStart", _calValues.Options.cyclic.Start, -1, s8inBounds, -10, 0);
validatedLoad("GPIOinMode", _calValues.Options.GPIOinMode, 0, u8inBounds, 0, 3);
validatedLoad("GPIOoutMode", _calValues.Options.GPIOoutMode, 0, u8inBounds, 0, 2);
validatedLoad("GPIOalgMode", _calValues.Options.GPIOalgMode, 0, u8inBounds, 0, 2);
validatedLoad("MenuonTimeout", _calValues.Options.HomeMenu.onTimeout, 0, u8inBounds, 0, 3);
validatedLoad("MenuonStart", _calValues.Options.HomeMenu.onStart, 0, u8inBounds, 0, 3);
validatedLoad("MenuonStop", _calValues.Options.HomeMenu.onStop, 0, u8inBounds, 0, 3);
validatedLoad("FrameRate", _calValues.Options.FrameRate, 1000, u16inBounds, 300, 1500);
preferences.end();
}
void
CESP32HeaterStorage::saveUI()
{
preferences.begin("user", false);
preferences.putLong("dimTime", _calValues.Options.dimTime);
preferences.putLong("menuTimeout", _calValues.Options.menuTimeout);
preferences.putUChar("degF", _calValues.Options.degF);
preferences.putUChar("thermoMethod", _calValues.Options.ThermostatMethod);
preferences.putUChar("enableWifi", _calValues.Options.enableWifi);
preferences.putUChar("enableOTA", _calValues.Options.enableOTA);
preferences.putChar("cyclicStop", _calValues.Options.cyclic.Stop);
preferences.putChar("cyclicStart", _calValues.Options.cyclic.Start);
preferences.putUChar("GPIOinMode", _calValues.Options.GPIOinMode);
preferences.putUChar("GPIOoutMode", _calValues.Options.GPIOoutMode);
preferences.putUChar("GPIOalgMode", _calValues.Options.GPIOalgMode);
preferences.putUChar("MenuOnTimeout", _calValues.Options.HomeMenu.onTimeout);
preferences.putUChar("MenuonStart", _calValues.Options.HomeMenu.onStart);
preferences.putUChar("MenuonStop", _calValues.Options.HomeMenu.onStop);
preferences.putUShort("FrameRate", _calValues.Options.FrameRate);
preferences.end();
}
bool
CESP32HeaterStorage::validatedLoad(const char* key, uint8_t& val, int defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, int min, int max, uint8_t mask)
{
val = preferences.getUChar(key, defVal);
if(!validator(val & mask, min, max)) {
DebugPort.print("CESP32HeaterStorage::validatedLoad<uint8_t> invalid read ");
DebugPort.print(key); DebugPort.print("="); DebugPort.print(val);
DebugPort.print(" validator("); DebugPort.print(min); DebugPort.print(","); DebugPort.print(max); DebugPort.print(") reset to ");
DebugPort.println(defVal);
val = defVal;
preferences.putUChar(key, val);
return false;
}
return true;
}
bool
CESP32HeaterStorage::validatedLoad(const char* key, int8_t& val, int defVal, std::function<bool(int8_t, int8_t, int8_t)> validator, int min, int max)
{
val = preferences.getChar(key, defVal);
if(!validator(val, min, max)) {
DebugPort.print("CESP32HeaterStorage::validatedLoad<uint8_t> invalid read ");
DebugPort.print(key); DebugPort.print("="); DebugPort.print(val);
DebugPort.print(" validator("); DebugPort.print(min); DebugPort.print(","); DebugPort.print(max); DebugPort.print(") reset to ");
DebugPort.println(defVal);
val = defVal;
preferences.putChar(key, val);
return false;
}
return true;
}
bool
CESP32HeaterStorage::validatedLoad(const char* key, uint16_t& val, int defVal, std::function<bool(uint16_t, uint16_t, uint16_t)> validator, int min, int max)
{
val = preferences.getUShort(key, defVal);
if(!validator(val, min, max)) {
DebugPort.print("CESP32HeaterStorage::validatedLoad<uint16_t> invalid read ");
DebugPort.print(key); DebugPort.print("="); DebugPort.print(val);
DebugPort.print(" validator("); DebugPort.print(min); DebugPort.print(","); DebugPort.print(max); DebugPort.print(") reset to ");
DebugPort.println(defVal);
val = defVal;
preferences.putUShort(key, val);
return false;
}
return true;
}
bool
CESP32HeaterStorage::validatedLoad(const char* key, long& val, long defVal, std::function<bool(long, long, long)> validator, long min, long max)
{
val = preferences.getLong(key, defVal);
if(!validator(val, min, max)) {
DebugPort.print("CESP32HeaterStorage::validatedLoad<long> invalid read ");
DebugPort.print(key); DebugPort.print("="); DebugPort.print(val);
DebugPort.print(" validator("); DebugPort.print(min); DebugPort.print(","); DebugPort.print(max); DebugPort.print(") reset to ");
DebugPort.println(defVal);
val = defVal;
preferences.putLong(key, val);
return false;
}
return true;
}
bool u8inBounds(uint8_t test, uint8_t minLim, uint8_t maxLim)
{
return (test >= minLim) && (test <= maxLim);
}
bool s8inBounds(int8_t test, int8_t minLim, int8_t maxLim)
{
return (test >= minLim) && (test <= maxLim);
}
bool u8Match2(uint8_t test, uint8_t test1, uint8_t test2)
{
return (test == test1) || (test == test2);
}
bool u16inBounds(uint16_t test, uint16_t minLim, uint16_t maxLim)
{
return (test >= minLim) && (test <= maxLim);
}
bool s32inBounds(long test, long minLim, long maxLim)
{
return (test >= minLim) && (test <= maxLim);
}
//#endif // ESP32

View file

@ -1,268 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __BTC_NV_STORAGE_H__
#define __BTC_NV_STORAGE_H__
#include "../RTC/Timers.h" // for sTimer
#include "GPIO.h"
struct sHeater {
uint8_t Pmin;
uint8_t Pmax;
uint16_t Fmin;
uint16_t Fmax;
uint8_t ThermostatMode;
uint8_t setTemperature;
uint8_t sysVoltage;
uint8_t fanSensor;
uint8_t glowDrive;
bool valid() {
bool retval = true;
retval &= Pmin < 100;
retval &= Pmax < 150;
retval &= Fmin < 5000;
retval &= Fmax < 6000;
retval &= ThermostatMode < 2;
retval &= setTemperature < 40;
retval &= sysVoltage == 120 || sysVoltage == 240;
retval &= fanSensor == 1 || fanSensor == 2;
retval &= glowDrive >= 1 && glowDrive <= 6;
return retval;
};
void init() {
Pmin = 14;
Pmax = 45;
Fmin = 1500;
Fmax = 4500;
ThermostatMode = 1;
setTemperature = 23;
sysVoltage = 120;
fanSensor = 1;
glowDrive = 5;
};
};
struct sHomeMenuActions {
uint8_t onTimeout;
uint8_t onStart;
uint8_t onStop;
bool valid() {
bool retval = true;
retval &= onTimeout < 4;
retval &= onStart < 4;
retval &= onStop < 4;
return retval;
}
void init() {
onTimeout = 0;
onStart = 0;
onStop = 0;
}
};
struct sCyclicThermostat {
int8_t Stop;
int8_t Start;
bool valid() {
bool retval = true;
retval &= Start >= -10 && Start <= 0;
retval &= Stop >= 0 && Stop <= 10;
return retval;
}
void init() {
Start = -1;
Stop = 0;
}
bool isEnabled() const {
return Stop != 0;
}
sCyclicThermostat& operator=(const sCyclicThermostat& rhs) {
Stop = rhs.Stop;
Start = rhs.Start;
return *this;
}
};
struct sBTCoptions {
long dimTime;
long menuTimeout;
uint8_t degF;
uint8_t ThermostatMethod; // 0: standard heater, 1: Narrow Hysterisis, 2:Managed Hz mode
uint8_t enableWifi;
uint8_t enableOTA;
uint8_t GPIOinMode;
uint8_t GPIOoutMode;
uint8_t GPIOalgMode;
uint16_t FrameRate;
sCyclicThermostat cyclic;
sHomeMenuActions HomeMenu;
bool valid() {
bool retval = true;
retval &= (dimTime >= -600000) && (dimTime < 600000); // +/- 10 mins
retval &= (menuTimeout >= 0) && (menuTimeout < 300000); // 5 mins
retval &= (degF == 0) || (degF == 1);
retval &= (ThermostatMethod & 0x03) < 3; // only modes 0, 1 or 2
retval &= (enableWifi == 0) || (enableWifi == 1);
retval &= (enableOTA == 0) || (enableOTA == 1);
retval &= GPIOinMode < 4;
retval &= GPIOoutMode < 3;
retval &= (FrameRate >= 300) && (FrameRate <= 1500);
retval &= cyclic.valid();
retval &= HomeMenu.valid();
return retval;
}
void init() {
dimTime = 60000;
menuTimeout = 60000;
degF = 0;
ThermostatMethod = 0;
enableWifi = 1;
enableOTA = 1;
GPIOinMode = 0;
GPIOoutMode = 0;
GPIOalgMode = 0;
FrameRate = 1000;
cyclic.init();
HomeMenu.init();
};
};
// the actual data stored to NV memory
struct sNVStore {
sHeater Heater;
sBTCoptions Options;
sTimer timer[14];
bool valid();
void init();
};
class CNVStorage {
public:
CNVStorage() {};
virtual ~CNVStorage() {};
virtual void init() = 0;
virtual void load() = 0;
virtual void save() = 0;
};
class CHeaterStorage : public CNVStorage {
protected:
sNVStore _calValues;
public:
CHeaterStorage();
virtual ~CHeaterStorage() {};
// TODO: These are only here to allow building without fully
// fleshing out NV storage for Due, Mega etc
// these should be removed once complete (pure virtual)
void init() {};
void load() {};
void save() {};
float getPmin();
float getPmax();
unsigned short getFmin();
unsigned short getFmax();
unsigned char getDesiredTemperature();
unsigned char getThermostatMode();
unsigned char getThermostatMethodMode();
float getThermostatMethodWindow();
unsigned char getSysVoltage();
unsigned char getFanSensor();
unsigned char getGlowDrive();
long getDimTime();
long getMenuTimeout();
unsigned char getDegFMode();
unsigned char getWifiEnabled();
unsigned char getOTAEnabled();
const sCyclicThermostat& getCyclicMode() const;
GPIOinModes getGPIOinMode();
GPIOoutModes getGPIOoutMode();
GPIOalgModes getGPIOalgMode();
uint16_t getFrameRate();
const sHomeMenuActions& getHomeMenu() const;
void setPmin(float);
void setPmax(float);
void setFmin(unsigned short val);
void setFmax(unsigned short val);
void setDesiredTemperature(unsigned char val);
void setThermostatMode(unsigned char val);
void setThermostatMethodMode(unsigned char val);
void setThermostatMethodWindow(float val);
void setSystemVoltage(float fVal);
void setFanSensor(unsigned char val);
void setGlowDrive(unsigned char val);
void setDimTime(long val);
void setMenuTimeout(long val);
void setDegFMode(unsigned char val);
void setWifiEnabled(unsigned char val);
void setOTAEnabled(unsigned char val);
void setCyclicMode(const sCyclicThermostat& val);
void setGPIOinMode(unsigned char val);
void setGPIOoutMode(unsigned char val);
void setGPIOalgMode(unsigned char val);
void setFrameRate(uint16_t val);
void setHomeMenu(sHomeMenuActions val);
void getTimerInfo(int idx, sTimer& timerInfo);
void setTimerInfo(int idx, const sTimer& timerInfo);
};
#ifdef ESP32
#include <Preferences.h>
#include <functional>
class CESP32HeaterStorage : public CHeaterStorage {
Preferences preferences;
public:
CESP32HeaterStorage();
virtual ~CESP32HeaterStorage();
void init();
void load();
void save();
void loadHeater();
void saveHeater();
void loadTimer(int idx);
void saveTimer(int idx);
void loadUI();
void saveUI();
bool validatedLoad(const char* key, int8_t& val, int defVal, std::function<bool(int8_t, int8_t, int8_t)> validator, int min, int max);
bool validatedLoad(const char* key, uint8_t& val, int defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, int min, int max, uint8_t mask=0xff);
bool validatedLoad(const char* key, uint16_t& val, int defVal, std::function<bool(uint16_t, uint16_t, uint16_t)> validator, int min, int max);
bool validatedLoad(const char* key, long& val, long defVal, std::function<bool(long, long, long)> validator, long min, long max);
};
#endif
extern CHeaterStorage& NVstore;
#endif // __BTC_NV_STORAGE_H__

View file

@ -1,82 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include <Arduino.h>
#include "../Protocol/Protocol.h"
#include "UtilClasses.h"
// a class to track the blue wire receive / transmit states
// class CommStates
void
CommStates::set(eCS eState)
{
_State = eState;
_Count = 0;
if(_report) {
static const char* stateNames[] = {
"Idle", "OEMCtrlRx", "OEMCtrlValidate", "HeaterRx1", "HeaterValidate1", "HeaterReport1",
"BTC_Tx", "HeaterRx2", "HeaterValidate2", "HeaterReport2", "TemperatureRead"
};
if(_State == Idle) DebugPort.println(""); // clear screen
DebugPort.print("State:");DebugPort.println(stateNames[_State]);
}
}
bool
CommStates::collectData(CProtocol& Frame, unsigned char val, int limit) { // returns true when buffer filled
Frame.Data[_Count++] = val;
return _Count >= limit;
}
bool
CommStates::collectDataEx(CProtocol& Frame, unsigned char val, int limit) { // returns true when buffer filled
// guarding against rogue rx kernel buffer stutters....
if((_Count == 0) && (val != 0x76)) {
DebugPort.println("First heater byte not 0x76 - SKIPPING");
return false;
}
Frame.Data[_Count++] = val;
return _Count >= limit;
}
bool
CommStates::checkValidStart(unsigned char val)
{
if(_Count)
return true;
else
return val == 0x76;
}
void
CommStates::setDelay(int ms)
{
_delay = millis() + ms;
}
bool
CommStates::delayExpired()
{
long test = millis() - _delay;
return(test >= 0);
}

View file

@ -1,236 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
* Copyright (C) 2018 James Clark
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "BTCWebServer.h"
#include "../Utility/DebugPort.h"
#include "../Protocol/TxManage.h"
#include "../Protocol/helpers.h"
#include "../cfg/pins.h"
#include "Index.h"
#include "../Utility/BTC_JSON.h"
#include "../Utility/Moderator.h"
#include <WiFiManager.h>
#if USE_SPIFFS == 1
#include <SPIFFS.h>
#endif
extern WiFiManager wm;
WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);
bool bRxWebData = false; // flags for OLED animation
bool bTxWebData = false;
const int led = 13;
#if USE_SPIFFS == 1
String getContentType(String filename) { // convert the file extension to the MIME type
if (filename.endsWith(".html")) return "text/html";
else if (filename.endsWith(".css")) return "text/css";
else if (filename.endsWith(".js")) return "application/javascript";
else if (filename.endsWith(".ico")) return "image/x-icon";
return "text/plain";
}
bool handleFileRead(String path) { // send the right file to the client (if it exists)
DebugPort.println("handleFileRead: " + path);
if (path.endsWith("/")) path += "index.html"; // If a folder is requested, send the index file
String contentType = getContentType(path); // Get the MIME type
if (SPIFFS.exists(path)) { // If the file exists
File file = SPIFFS.open(path, "r"); // Open it
size_t sent = server.streamFile(file, contentType); // And send it to the client
file.close(); // Then close the file again
return true;
}
DebugPort.println("\tFile Not Found");
return false; // If the file doesn't exist, return false
}
/*void handleFavIcon() {
handleFileRead("/favicon.ico");
}*/
void handleBTCRoot() {
handleFileRead("/index.html");
/* if(SPIFFS.exists("/index.html")) {
File html = SPIFFS.open("/index.html");
server.streamFile(html, "text/html");
html.close();
}
else {
DebugPort.println("\"/index.html\" does not exist!!!");
}*/
}
#else
void handleBTCRoot() {
String s = MAIN_PAGE; //Read HTML contents
server.send(200, "text/html", s); //Send web page
}
#endif
void handleWMConfig() {
server.send(200, "text/plain", "Start Config Portal - Retaining credential");
DebugPort.println("Starting web portal for wifi config");
delay(500);
// wm.startWebPortal();
wifiEnterConfigPortal(true, false, 3000);
}
void handleReset() {
server.send(200, "text/plain", "Start Config Portal - Resetting Wifi credentials!");
DebugPort.println("diconnecting client and wifi, then rebooting");
delay(500);
//client.disconnect();
// wifi_station_disconnect();
// wm.disconnect();
// wm.resetSettings();
wifiEnterConfigPortal(true, true, 3000);
}
void handleFormat() {
server.send(200, "text/plain", "Formatting SPIFFS partition!");
DebugPort.println("Formatting SPIFFS partition");
delay(500);
SPIFFS.format();
//client.disconnect();
// wifi_station_disconnect();
// wm.disconnect();
// wm.resetSettings();
}
void handleBTCNotFound() {
digitalWrite(led, 1);
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
digitalWrite(led, 0);
}
void initWebServer(void) {
if (MDNS.begin("BTCHeater")) {
DebugPort.println("MDNS responder started");
}
// server.on("/", handleBTCRoot);
server.on("/wmconfig", handleWMConfig);
server.on("/resetwifi", handleReset);
server.on("/formatspiffs", handleFormat);
#if USE_SPIFFS == 1
// NOTE: this serves the default home page, and favicon.ico
server.onNotFound([]()
{ // If the client requests any URI
if (!handleFileRead(server.uri())) // send it if it exists
server.send(404, "text/plain", "404: Not Found"); // otherwise, respond with a 404 (Not Found) error
}
);
#else
server.onNotFound(handleBTCNotFound);
#endif
server.begin();
webSocket.begin();
webSocket.onEvent(webSocketEvent);
DebugPort.println("HTTP server started");
}
unsigned char cVal;
// called my main sketch loop()
bool doWebServer(void) {
webSocket.loop();
server.handleClient();
}
bool isWebServerClientChange()
{
static int prevNumClients = -1;
int numClients = webSocket.connectedClients();
if(numClients != prevNumClients) {
prevNumClients = numClients;
DebugPort.println("Changed number of web clients, should reset JSON moderator");
return true;
}
return false;
}
bool sendWebServerString(const char* Str)
{
unsigned long tStart = millis();
if(webSocket.connectedClients()) {
unsigned long tCon = millis() - tStart;
tStart = millis();
bTxWebData = true; // OLED tx data animation flag
webSocket.broadcastTXT(Str);
unsigned long tWeb = millis() - tStart;
// DebugPort.print("Websend times : "); DebugPort.print(tCon); DebugPort.print(","); DebugPort.println(tWeb);
return true;
}
return false;
}
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
if (type == WStype_TEXT) {
bRxWebData = true;
char cmd[256];
memset(cmd, 0, 256);
for (int i = 0; i < length && i < 256; i++) {
cmd[i] = payload[i];
}
interpretJsonCommand(cmd); // send to the main heater controller decode routine
}
}
bool hasWebClientSpoken(bool reset)
{
bool retval = bRxWebData;
if(reset)
bRxWebData = false;
return retval;
}
bool hasWebServerSpoken(bool reset)
{
bool retval = bTxWebData;
if(reset)
bTxWebData = false;
return retval;
}

View file

@ -1,331 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2019 Ray Jones
* Copyright (C) 2019 James Clark
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
// Should be working - Jimmy C
#include "BTCWifi.h"
#include "../Utility/DebugPort.h"
#include <DNSServer.h>
#include "../OLED/ScreenManager.h"
#include "esp_system.h"
#include <Preferences.h>
#include "../Utility/NVStorage.h"
#define USE_AP
// function to control the behaviour upon reboot if no wifi manager credentials exist
// or connection fails
void prepBootIntoConfigPortal(bool state);
bool shouldBootIntoConfigPortal();
void saveParamsCallback();
void APstartedCallback(WiFiManager*);
WiFiManager wm;
bool isPortalAP = false; // true if config portal is running
bool isSTA = false; // true if connected to an access point
int TRIG_PIN; // pin that triggers the configuration portal when set to LOW
unsigned restartServer = 0; // set to time of portal reconfig - will cause reboot a while later
char MACstr[2][20]; // MACstr[0] STA, MACstr[1] = AP
int wifiButtonState = 0;
extern CScreenManager ScreenManager;
bool initWifi(int initpin,const char *failedssid, const char *failedpassword)
{
TRIG_PIN = initpin;
pinMode(TRIG_PIN, INPUT_PULLUP);
// report the MAC addresses - note individual values for STA and AP modes
uint8_t MAC[6];
esp_read_mac(MAC, ESP_MAC_WIFI_STA);
sprintf(MACstr[0], "%02X:%02X:%02X:%02X:%02X:%02X", MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]);
DebugPort.print(" STA MAC address: "); DebugPort.println(MACstr[0]);
esp_read_mac(MAC, ESP_MAC_WIFI_SOFTAP);
sprintf(MACstr[1], "%02X:%02X:%02X:%02X:%02X:%02X", MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]);
DebugPort.print(" AP MAC address: "); DebugPort.println(MACstr[1]);
char APname[32];
sprintf(APname, "%s", failedssid);
//reset settings - wipe credentials for testing
// wm.resetSettings();
// Automatically connect using saved credentials:
// WiFiManager will prepare a link connection, using stored credentials if available.
//
// NO CREDENTIALS:
// Using a stored NV variable, we control the link creation via wm.setEnableConfigPortal():
// true - SoftAP is created (SSID = failedssid), and linked to the config portal
// false - we need to create a Soft AP, the portal does not start, we provide a web server
//
// WITH CREDENTIALS:
//
// Connected to stored AP, AP provides an IP address to use, we are STA (station)
// failed to connect to stored AP, using a stored NV variable we control the behaviour via wm.setEnableConfigPortal():
// true - SoftAP is created (SSID = failedssid), and linked to the config portal
// false - we need to create a Soft AP, the portal does not start, we provide a web server
DebugPort.println("Attempting to start STA mode (or config portal) via WifiManager...");
// wm.setHostname(failedssid);
wm.setHostname(APname);
wm.setConfigPortalTimeout(20);
wm.setConfigPortalBlocking(false);
wm.setSaveParamsCallback(saveParamsCallback); // ensure our webserver gets awoken when IP config changes to STA
wm.setAPCallback(APstartedCallback);
wm.setEnableConfigPortal(shouldBootIntoConfigPortal());
//REMOVED - UNSTABLE WHETHER WE GET 192.168.4.1 or 192.168.100.1 ????
// REMOVED wm.setAPStaticIPConfig(IPAddress(192, 168, 100, 1), IPAddress(192, 168, 100, 1), IPAddress(255,255,255,0));
// bool res = wm.autoConnect(failedssid, failedpassword); // auto generated AP name from chipid
bool res = wm.autoConnect(APname, failedpassword); // auto generated AP name from chipid
DebugPort.print("WifiMode after autoConnect = "); DebugPort.println(WiFi.getMode());
int chnl = 1;
bool retval = false;
if(!res) {
// failed STA mode
DebugPort.println("WiFimanager failed STA connection. Setting up AP...");
WiFi.disconnect(); // apparently needed for AP only OTA to reboot properly!!!
}
else {
// runs through here if STA connected OK
// if you get here you have connected to the WiFi
isSTA = true;
DebugPort.println("WiFiManager connected in STA mode OK");
DebugPort.print(" STA IP address: "); DebugPort.println(WiFi.localIP());
// must use same radio channel as STA to go to STA+AP, otherwise we drop the STA!
chnl = WiFi.channel();
DebugPort.print("Now promoting to STA+AP mode");
retval = true;
}
#ifdef USE_AP
// always setup an AP - for STA+AP mode we *must* use the same RF channel as STA
DebugPort.println("Starting AP mode");
//REMOVED - UNSTABLE WHETHER WE GET 192.168.4.1 or 192.168.100.1 ????
// REMOVED WiFi.softAPConfig(IPAddress(192, 168, 100, 1), IPAddress(192, 168, 100, 1), IPAddress(255,255,255,0));
// WiFi.softAP(failedssid, failedpassword, chnl);
WiFi.softAP(APname, failedpassword, chnl);
WiFi.enableAP(true);
DebugPort.print(" AP SSID: "); DebugPort.println(WiFi.softAPgetHostname());
DebugPort.print(" AP IP address: "); DebugPort.println(WiFi.softAPIP());
DebugPort.print("WifiMode after initWifi = "); DebugPort.println(WiFi.getMode());
#endif
// even though we may have started in STA mode - start the config portal if demanded via the NV flag
if(shouldBootIntoConfigPortal()) {
DebugPort.println("Manually starting web portal");
wm.startWebPortal();
isPortalAP = true; // we started portal, we have to flag it!
}
return retval;
}
// call from main sketch loop()
void doWiFiManager()
{
wm.process();
// manage handling of pin to enter WiFManager config portal
// we typically use the BOOT pin for this (pins.h)
//
// Quick Press (< 1 sec) - enable config portal
// > 1 second (< 5 sec) press - disable config portal
// > 5 second press - erase credentials, enable config portal
static bool pinDown = false;
static long pinTime = 0;
unsigned long tDelta;
if(digitalRead(TRIG_PIN) == LOW) {
if(!pinDown) {
pinTime = millis();
ScreenManager.reqUpdate();
}
pinDown = true;
// track hold duration - change OLED Wifi annotation according to length of press
tDelta = millis() - pinTime;
if(tDelta > 5000)
wifiButtonState = 3; // we will show 'ERS' on OLED!
else if(tDelta > 1000)
wifiButtonState = 2; // we will show 'HTR' on OLED!
else
wifiButtonState = 1; // we will show 'CFG' on OLED!
}
else {
if(pinDown) {
pinDown = false;
tDelta = millis() - pinTime;
DebugPort.print("Wifi config button tDelta = "); DebugPort.println(tDelta);
// > 5 second press?
if(tDelta > 5000) {
wifiEnterConfigPortal(true, true); // very long press - clear credentials, reboot into portal
}
// > 1 second press?
else if(tDelta > 1000) {
wifiEnterConfigPortal(false); // long press - reboot into web server
}
// > 50ms press?
else if(tDelta > 50) {
wifiEnterConfigPortal(true); // quick press - reboot into portal
}
// consider as contact bounce if < 50ms!
}
}
}
void wifiDisable(long rebootDelay)
{
NVstore.setWifiEnabled(0);
NVstore.save();
DebugPort.println("*** Disabling WiFi ***");
restartServer = (millis() + rebootDelay) | 1; // prepare to reboot in the future - ensure non zero!
const char* content[2];
content[0] = "WiFi Mode \032 DISABLED";
content[1] = "";
ScreenManager.showRebootMsg(content, rebootDelay);
}
void wifiEnterConfigPortal(bool state, bool erase, long rebootDelay)
{
wm.disconnect();
NVstore.setWifiEnabled(1);
NVstore.save();
prepBootIntoConfigPortal(state);
const char* content[2];
if(isWifiSTA() && !erase)
content[0] = "WiFi Mode \032 STA+AP";
else
content[0] = "WiFi Mode \032 AP only";
if(erase) {
wm.resetSettings();
DebugPort.println("*** Erased wifi credentials ***");
}
if(state) {
DebugPort.println("*** Rebooting into config portal ***");
content[1] = "Web \032 Config Portal";
}
else {
DebugPort.println("*** Rebooting into web server ***");
content[1] = "Web \032 Heater control";
}
restartServer = (millis() + rebootDelay) | 1; // prepare to reboot in the future - ensure non zero!
ScreenManager.showRebootMsg(content, rebootDelay);
}
// callback is invoked by WiFiManager after new credentials are saved and verified
void saveParamsCallback()
{
wifiEnterConfigPortal(false); // stop config portal, reboot
}
// callback called if the WiFiManager started the config portal
void APstartedCallback(WiFiManager*)
{
isPortalAP = true; // will add CFG adornment to OLED WiFi icon
}
const char* getWifiAPAddrStr()
{
noInterrupts();
IPAddress IPaddr = WiFi.softAPIP(); // use stepping stone - function returns an automatic stack var - LAME!
interrupts();
return IPaddr.toString().c_str();
}
const char* getWifiSTAAddrStr()
{
noInterrupts();
IPAddress IPaddr = WiFi.localIP(); // use stepping stone - function returns an automatic stack var - LAME!
interrupts();
return IPaddr.toString().c_str();
}
const char* getWifiAPMACStr()
{
return MACstr[1];
}
const char* getWifiSTAMACStr()
{
return MACstr[0];
}
bool isWifiConnected()
{
return WiFi.status() == WL_CONNECTED;
}
bool isWifiAP()
{
int mode = WiFi.getMode();
return !isSTA && ((mode & WIFI_MODE_AP) != 0);
}
bool isWifiSTA()
{
return isSTA; // true: STAtion mode link is active
}
bool isWifiConfigPortal()
{
return isPortalAP; // true: config portal is running
}
// save an NV flag to determine whether config portal should run after reboot
void prepBootIntoConfigPortal(bool state)
{
Preferences NV;
NV.begin("user");
NV.putBool("bootPortal", state);
NV.end();
DebugPort.print("Setting boot config portal if WiFiManager fails = "); DebugPort.println(state);
}
// test the NV flag whether the config portal should run after reboot
bool shouldBootIntoConfigPortal()
{
Preferences NV;
NV.begin("user");
bool retval = NV.getBool("bootPortal", false);
NV.end();
DebugPort.print("Boot config portal if WiFiManager fails = "); DebugPort.println(retval);
return retval;
}
int isWifiButton()
{
return wifiButtonState;
}

View file

@ -1,46 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 James Clark
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __BTCWIFI_H__
#define __BTCWIFI_H__
#include <Arduino.h>
#include <WiFiManager.h>
#include <WiFi.h>
void doWiFiManager();
bool initWifi(int initpin,const char *failedssid, const char *failedpassword);
const char* getWifiAPAddrStr();
const char* getWifiSTAAddrStr();
const char* getWifiAPMACStr();
const char* getWifiSTAMACStr();
bool isWifiConnected();
bool isWifiAP();
bool isWifiSTA();
bool isWifiConfigPortal();
bool isWebClientConnected();
bool hasWebClientSpoken(bool reset = false);
bool hasWebServerSpoken(bool reset = false);
void wifiEnterConfigPortal(bool state, bool erase = false, long timeout = 7000);
void wifiDisable(long rebootDelay = 7000);
int isWifiButton();
#endif __BTCWIFI_H__

View file

@ -1,86 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 James Clark
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "BTCota.h"
#include "../cfg/BTCConfig.h"
#if USE_SPIFFS == 1
#include <SPIFFS.h>
#endif
extern void ShowOTAScreen(int percent=0);
#include <esp_int_wdt.h>
#include <esp_task_wdt.h>
void hard_restart() {
esp_task_wdt_init(1,true);
esp_task_wdt_add(NULL);
while(true);
}
void initOTA(){
// ArduinoOTA.setHostname("myesp32");
ArduinoOTA.setHostname("BTCOTA");
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
SPIFFS.end();
DebugPort.println("Start updating " + type);
DebugPort.handle(); // keep telnet spy alive
ShowOTAScreen();
})
.onEnd([]() {
DebugPort.println("\nEnd");
DebugPort.handle(); // keep telnet spy alive
delay(100);
// DebugPort.end(); // force graceful close of telnetspy - ensures a client will reconnect cleanly
})
.onProgress([](unsigned int progress, unsigned int total) {
int percent = (progress / (total / 100));
DebugPort.printf("Progress: %u%%\r", percent);
DebugPort.handle(); // keep telnet spy alive
ShowOTAScreen(percent);
})
.onError([](ota_error_t error) {
DebugPort.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) DebugPort.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) DebugPort.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) DebugPort.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) DebugPort.println("Receive Failed");
else if (error == OTA_END_ERROR) DebugPort.println("End Failed");
DebugPort.handle(); // keep telnet spy alive
});
ArduinoOTA.begin();
}
void DoOTA(){
ArduinoOTA.handle();
};

View file

@ -1,56 +0,0 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <driver/adc.h>
const uint8_t UART_Tx = 1;
const uint8_t LED_Pin = 2;
const uint8_t UART_Rx = 3;
const uint8_t HC05_KeyPin = 4;
const uint8_t TxEnbPin = 5;
const uint8_t Tx433MHz_pin = 12; // HSPI std pins
const uint8_t Rx433MHz_pin = 13; // "
const uint8_t GPIOout2_pin = 14; // "
const uint8_t DS18B20_Pin = 15;
const uint8_t Rx1Pin = 16;
const uint8_t Tx1Pin = 17;
const uint8_t Tx2Pin = 18;
const uint8_t Rx2Pin = 19;
const uint8_t OLED_SDA_pin = 21; // I2C std pins
const uint8_t OLED_SCL_pin = 22; // "
const uint8_t HC05_SensePin = 23;
const uint8_t GPIOin2_pin = 25;
const uint8_t GPIOin1_pinV21V10 = 26;
const adc2_channel_t GPIOalg_pinINVALID = ADC2_CHANNEL_9; // GPIO 26 - Cannot use ADC2 with WiFi enabled!!!
const uint8_t GPIOout1_pin = 27;
const uint8_t keyUp_pin = 32;
const uint8_t GPIOin1_pinV20 = 33;
const adc1_channel_t GPIOalg_pin = ADC1_CHANNEL_5; // GPIO 33 - OK with Wifi, ADC1 channel
const uint8_t keyDown_pin = 34; // input only, no chip pullup
const uint8_t keyCentre_pin = 35; // input only, no chip pullup
const uint8_t keyRight_pin = 36; // input only, no chip pullup
const uint8_t keyLeft_pin = 39; // input only, no chip pullup
//const uint8_t ListenOnlyPin = 33;
const uint8_t WiFi_TriggerPin = 0; // BOOT switch!

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1 +1,5 @@
esptool.exe --chip esp32 --port COM11 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xe000 boot_app0.bin 0x1000 bootloader_qio_80m.bin 0x10000 Afterburner.bin 0x8000 Afterburner.partitions.bin
REM Firmware
esptool.exe --chip esp32 --port COM5 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xe000 boot_app0.bin 0x1000 bootloader_qio_80m.bin 0x10000 AfterburnerV3.1.9.bin 0x8000 Afterburner.partitions.bin
REM SPIFFS
esptool.exe --chip esp32 --port COM5 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_size detect 0x3d0000 spiffs.bin

22
Bootload/Checklist.txt Normal file
View file

@ -0,0 +1,22 @@
Afterburner operation checklist
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OLED intact
Latest firmware uploaded
SPIFFS uploaded
Check temperature sensor
Keypad functions OK
Indicator LEDs function
Web server functions and serves heater control page
Bluetooth pairs and streams SPP data
Set time
Install battery
GPIO units only
~~~~~~~~~~~~~~~
Check pressure sensor
GPIO functions:
Input x2
Output x2
Analogue

View file

@ -1 +1 @@
espota.exe -i 192.168.20.100 -p 3232 --auth= -f Afterburner.bin
espota.exe -i 192.168.1.1 -p 3232 --auth= -f AfterburnerV3.0.1.bin

1
Bootload/OTA_AP.bat Normal file
View file

@ -0,0 +1 @@
espota.exe -i 192.168.4.1 -p 3232 --auth= -f AfterburnerV3.0.1.bin

BIN
Bootload/boot_app0.bin Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

16
BuildREADME.txt Normal file
View file

@ -0,0 +1,16 @@
This directory structure includes an Arduino path, and a src path.
The Arduino path is only to support builing with the restrictive Arduino IDE.
The src path is for the awesome PlatformIO under VScode.
Use it, you will not regret it.
Arduino builds are sloooooowwwww.
Do it that way if you must, but seriously don't!
PlatformIO rocks - just load the root repo directory with PIO in VScode
and away you go.
The Arduino\Afterburner\Afterburner.ino file is a hard symbolic link to the
proper src\Afterburner\Afterburner.cpp file.
Likewise the Arduino\Afterburner\src and Arduino\Afterburner\data paths are
hard junctions to the src\Afterburner\src and src\Afterburner\data files.

BIN
CRCgen/AfterBurnerCRC.cpp Normal file

Binary file not shown.

11
CRCgen/Readme.txt Normal file
View file

@ -0,0 +1,11 @@
AfterburnerCRC.cpp is used to append a CRC-16 value to the
compiled binary file.
This CRC is used to confirm the binary image uploaded to the
Afterburner was genuinely intended for the Afterburner.
Naively attempting to upload the direct compiled output binary
will result in rejection of the upload attempt.
You will need to compile Afterburner.cpp and copy the resultant
executable to the repository root (adjacent to plaformio.ini)

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 KiB

BIN
Documentation/3pinplug.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

BIN
Documentation/BTC1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

BIN
Documentation/BTC2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

BIN
Documentation/BTCavatar.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
Documentation/Battery.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
Documentation/Battery2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 KiB

BIN
Documentation/BlackLCD.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

BIN
Documentation/BlueLCD.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

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