Only initialize MDNS, WebLog, and OTA when first connecting to WiFi. Do not re-initialize upon re-connections after a disconnect.
Also, add number of disconnects, and reset_reason() to WebLog
The only reason to have used getAccessory(aid) is to delete it, so the delete command is now invoked automatically. Function returns 0 on success (matching aid found) or -1 on fail (aid not found)
Method homeSpan.updateDatabase(boolean updateMDNS) recomputes database hash and compares with previous hash. If changed, config number is updated and saved in NVS along with new hash. If updateMDNS is true, a new "c#" MDNS record is also broadcast with the new config number. This triggers HomeKit to call for a database refresh. Method returns true if config number has changed, or false if it has not.
The "C" command computes a hash of the current database config and updates the config number if needed. If config number has changed, the MDNS "c#" record is updated and the new config number is rebroadcast. This triggers HomeKit to immediately request an update of the HAP database so that the changes can be shortly reflected in the Home App without the need to close any Client connections or reboot the device.
The config number logic has also been updated/fixed. Previously it would create a hash from the full HAP database, which includes the value of each characteristic. Thus, initial value changes of Characteristics, as a result of stored values in NVS, would cause an update to the config number upon reboot.
This is not problematic, but also not intended, as a change in value is not really a change in the database config. The new logic computes a hash of the database that EXCLUDES all Characteristic values.
Instead of creating a static configLog for display upon start-up, an info log will be generated based on real-time data whenever the 'i' CLI command is requested. This provides for more streamlined error-checking as well.
Rather than call homeSpan.poll() in the main Arduino loop() function, you can instead call homeSpan.start() at the end of the set-up function. This keeps the main Arduino loop() function free for user-defined code that will not block, and does not get blocked by, homeSpan.poll().
If using a dual-core processor, polling now occurs on core 0, instead of the core 1 (where all other Arduino stuff normally runs).
HomeSpan will throw a fatal error and halt processing if both homeSpan.poll() and homeSpan.start() are used in the same sketch.
Rather than auto-enable OTA if not already enabled in safemode, changed the logic to simply rollback to previous app if OTA was used to download a sketch that does not itself have OTA enabled, unless OTA was previously enabled without safemode.
To do: Delete all complicated SpanOTA logic that (unsuccessfully) tried to track OTA status and check SHA246 partition codes to determine if reboot was OTA or Serial. None of this is need, but some of the code may be useful for other things in the future.
Since much of the Arduino-ESP32 library is precompiled, you cannot use -DCONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE to define this during compile time (it gets defined but is not used by the precompiled libraries).
TO DO: create an NVS entry that flags whether last update was via OTA. If so, automatically enable OTA regardless of enableOTA setting. This would ensure that OTA cannot be disabled accidentally by uploading a non-enabledOTA sketch to remote device.
Also updated SpanWebLog::addLog() so that the log message is also output to the Serial Monitor if the HomeSpan Log Level is set to 1 or greater.
To do: DOCUMENT ALL THIS!
Gets IP address (as char *) of last client to send a request. Useful as part of web log messages. Will return 0.0.0.0 if used outside of any code that is responding to a client request.
Added isEnabled to SpanWebLog to indicate whether Web Log has been enabled. This allows the use of homeSpan.webLog.addLog() without ever enabling (in which case the log entries are ignored).
Also included logic so that clockTime is set to "Unknown" is addLog() is called prior to WiFi being established.
Next up: replace addLog(const char *) with a variadic set of parameters with dynamic storage allocation.
Also, updated error checking so that the UUID for both custom Services and custom Characteristics are checked for syntax. A fatal error is thrown if an ill-formatted UUID is found, since this will definitely prevent pairing with the HomeApp.
The UUID for HAP Services and Characteristics are NOT error checked, since these are fixed in HomeSpan.
Also, the custom Characteristics are not validated against the optional list for a service. If the user adds a custom Characteristic to a HAP Service, it is assumed to be valid. Similarly, none of the Characteristics (HAP of Custom) in a Custom Service are validated at all.
Use homeSpan.reserveSocketConnections(n) to reserve n sockets *not* to be used for HAP. Multiple calls can be used to cumulate a total number of reserved sockets. This makes is easy to add reserveSocketConnections(n) at multiple point in the code whenever a certain number of sockets need to be reserved for use with that portion of the code. For example enableOTA() calls reserveSocketConnections(1).
If both setMaxConnections(), and one or more reserveSocketConnections(), methods are called HomeSpan will use the more restrictive net value.
Optional method to automatically turn off Status LED after a *duration* seconds. LED will resume normal operation any time it is re-triggered with a new pattern. This also resets the elapsed time used to check for autoOff.
Added true/false parsing to all integer-based Characteristics. Previously true/false was only parsed for BOOL Characteristics. For integer-based on/off Characteristics, the Home App would send a 0 for off, and a 1 for on, consistent with HAP-R2. BUT...when using Home App AUTOMATIONS, the Home App would send true/false for integer-based Characteristics, which is inconsistent with HAP-R2. This meant automations worked with lights (that use the boolean ON Characteristic) but not with fans (that use the uint8 ACTIVE Characteristic).
With this "fix", true/false will be recognized all the time (except for float- and string-based Characteristics. Confirmed that fans now work with Home App Automations.
Ranges are now checked for all Characteristics at the end of the configuration, instead of at the end of each Accessory definition. This is much cleaner and the output is easier to read.
To do: Revisit use of REQ and OPT - what should constitute a fatal error and what should be a warning.
To do: Revisit Character definitions - attempt to normalize using the methods implemented for Custom Characteristics
No need to specify both FORMAT and TYPE. For example, specifying UINT16 automatically sets type to be uint16_t.
To do: Explore if this can be used for standard Characteristics - revisit standard Characteristics definitions and structure to see if it can be simplified.
Re-worked code to allow for NO Status LED Pin and NO Control Pin. If Control Pin is not set explicitly with homeSpan.setControlPin(), there will be no Control Pin. There is no longer a default since there are too many board variations with S2 and C3 chips now supported. Same for Status Pin - it will not be defined unless set explicitly with homeSpan.setStatusPin(), with the exception that if LED_BUILTIN is defined (i.e. there is a built-in LED), then the Status LED Pin will default to LED_BUILTIN if not explicitly defined. MUST UPDATE DOCUMENTATION - THIS CHANGES DEFAULT BEHAVIOR OF HOMESPAN AND MAY REQUIRE UPDATES TO EXISTING SKETCHES
Simplified enableAutoStartAP() so it no longer takes any arguments. It now simply enables the auto launch of the WiFi Access Point at start-up if WiFi Credentials are not found.
New method setApFunction() will now be used to set an alternative method for the WiFi Access Point. This will be called anytime 'A' is typed into the CLI, which also covers the auto-launch of the AP at start-up a well as starting it via the Control Button, since both of these functions call processCommand('A').
To enable save/restore for a Characteristic, set second parameter to TRUE when instantiating. Since first parameter was optional as well, this requires setting it as well.
Next up: Must add logic to setVal() to store new value as well.