OTA pasword now stored in NVS. Use 'O' command to change from default. Note password is stored as MD5 hash, and is therefore unrecoverable. Changes to password DO NOT take effect until next reboot. Password CAN be changed even if OTA has not been enabled for sketch. Blank passwords are not allowed.
Stored password can only be erased with 'E' command.
Setup ID can now be stored in NVS and set dynamically with the 'Q' command. However, homeSpan.setQRID(char *id) will override if present, but will not change the default stored in the NVS. This default wil be used once again if homeSpan.setQRID() is removed from the sektch.
If the NVS is empty, the default is set to "HSPN" as in version 1.1.4.
Class used for the creation and storage of a pairing QR Code (just the text, not the actual graphic) from a HAP Setup Code, HAP Category, and HAP Setup ID. The resulting QR Code text is output to Serial Monitor whenever the SetUp Code is generated or changed. The user can type this text into any QR Generator to create a QR Code graphic for pairing the device to HomeKit (in lieu of creating a printed tag of the Setup Code formatted using the Scancardium font).
Though not needed for HomeSpan, this class implements all the settings and parameters (such as Version and Reserved) used to generate any Apple HomeKit QR Code.
This class is used internally by HomeSpan and is not intended for the end-user.
HomeSpan now broadcasts a Hashed Setup ID as MDNS "sh", which is used when pairing with a QR Code instead of a Setup Code. A text version of the resulting QR code is output to the Serial Monitor whenever the 9-digit Setup Code is generated or changed. The text version of the QR code can then be input into any QR Code Generator to create a pairable QR Code.
The default Setup ID used to create the Hashed Setup ID is "HSPN". This can be changed with homeSpan.setQRCode(const char *id), where id is exactly 4 alphanumeric characters. If not, the request to change the Setup ID is silently ignored and remains "HSPN."
HomeSpan defaults to running the HAP Server on port 80 (the standard HTTP port). This method allows the user to over-ride the default and have HomeSpan run the HAP Server on any other port.
ALSO: In updating this portion of the code, identified an additional parameter to the ESP32 version of WiFiServer that allows one to specify the number of simultaneous Server connections. The ESP32 default is 4, which suggests that the ESP32 was internally juggling connections that HomeSpan was keeping open (since the HomeSpan default is 8 connections).
This WiFiServer call has been updated to now specify both the port number AND the number of maximum simultaneous connections (to match whatever has been set by HomeSpan). This may or may not result in improving performance when more than 4 clients are connected.
LED_BUILTIN is NOT defined for all ESP32 boards - some do not have a built-in LED! Instead, Status LED now defaults to Pin 13, as opposed to LED_BUILTIN. Also, added a new method, homeSpan.getStatusPin(), to return the pin number used for the Status LED, whether or not it remains the default (13) or is changed by user with homeSpan.setStatusPin(pin). This method is now used in the DEV_Identify.h file for each example, instead of using LED_BUILTIN (which otherwise won't compile for boards without a built-in LED)
WiFi connection now occurs asynchronously so that if WiFi is lost, or cannot be connected at start-up, the device still operates intead of blocking while it tries to connect. The new logic should allow for a wider range of chips to connect.
Program now halts if more than 41 Accessories are defined. This allows for a bridge to have 40 Accessories. HAP limit is 150, but there is not enough memory in ESP32 to robustly handle more (testing up to 50 LightBulb Services worked, but was sluggish).
1) Used `const char *` instead of `char *` where appropriate, including the need to create a dummy blank string for us in certain places.
2) Set initialization of WiFiClient to 0 instead of NULL, since WiFiClient is not a pointer (probably don't need to set it to anything since WiFiClient overrides the boolean operator anyway).
3) Cleaned up some of the messaging and logic when WiFi tries to connect so that users know to wait a bit.
4) Only remaining warning messages are for casting SpanService to (void *), which I think i unavailable (and is not forbidden).
To Do: Go through examples and check for warnings (will likely need to convert `char *` to `const char *` in many places.
* if Accessory ID is NOT specified, the default is aid=1+aid of last Accessory, with aid of very first Accessory always set to 1.
* aid of first Accessory must ALWAYS be set to 1 - if user over-rides with another value, error will be thrown
* validation now includes checking for duplicate aids, as well as ensuring the first Accessory is always aid=1
If not specified, "aid" defaults to an index number representing the order in which the Accessories were created. Values are stored as uint32_t (which is more limited than HAP requirements of uint64_t, but makes the code easier).
TO DO: Must add validation to ensure duplicate aid values are not used.
button(int pin, boolean isLong) changed to button(int pin, int pressType), where pressType can be SpanButton::LONG, SpanButton::SINGLE, or SpanButton::DOUBLE. Updated Example 16 and confirmed everything works as expected.
To do: Review all prior examples and update SpanButton when needed. Also need to update Zephyr Vent Hood code!
Added ServiceLabelIndex Characteristic, which seems to be required as noted in HAP specifications. However, linking to a ServiceLabel Service does not appear to be required, so there is no need to build any Service-Linking logic into homeSpan - will wait for use-case to be identified.
To do: Add support for double-click to SpanButton, then include in Example 16.
Modified SpanCharacteristic::sprintfAttributes to streamline logic and add special handling for the ProgrammableSwitchEvent Characteristic as required by HAP: the value returned for the database or any read request must be set to null (i.e. "value":null). The only time the real value should be returned is when the device sends a EV/Notify message (when the button is pressed). Verified that the example works as expected!
TO DO: Add functionality to allow for Service Namespace and Index label so that you can have multiple programmable pushbuttons in one service - this requires logic for HAP LINKED SERVICE functionality.
Added validation to ensure all Accessories have a AccessoryInformation Service and all Accessories have a HAPProtocolInformation Service, unless the device is configured as a bridge, in which case only the first Accessory requires a HAPProtocolInformation Service.
Checks to ensure that: (A) Characteristic is allowable (i.e. either required or optional) for the defined Service, and (B) Characteristic has not already been instantiated for the defined Service.
The 'A' command now resets any existing WiFi functionality so that it can start an Access Point without needing to first reboot.
To Do: Add a method to cancel out of apConfigure() and reboot by pressing control button.
To Do: Create time-out for commandMode()
Changing code so that it is possible to run HomeSpan without configuring WiFi. HomeSpan can already run without being paired, but requires WiFi at start-up. No reason to force WiFi to be used if device has buttons to operate the appliance withouth the need for WiFi or a connection to HomeKit. Work in progress...
Zephyr3, the latest version, was moved into its own repo and renamed ZephyrVentHood.
Deleted Zephyr1, Zephyr2, and Zephyr3, which are no longer needed.
Flattened folder structure for Examples and placed them all in top-level directory
Started adding lists to the first few Services in Service.h. This is a longer-term project to enable HomeSpan to validate a configuration and check that all Services have all required Characteristics and that any optional Characteristics defined are indeed permitted.
Full initialization now depends on "isInitialized" flag instead of monitoring Wifi connection, to protect against a loss of WiFi causing a re-initialization, instead of just a wifi reconnect with initWifi() alone.
SpanButton now instantiates PushButton instead of keeping track of its own triggering logic. This means that SpanButton longPress() is triggered by holding down the button for longTime WITHOUT the need to release. This is a desired change.
Next: Must update Example 15 to state that SpanButtons trigger a long press withouth needing to be released.
To do: Consider adding a "repeating mode" for longPress in which the SpanButton re-triggers every longTime while button continues to be pressed. Best way to implement is probably by creating a PushButton::extend() method.
Also moved StatusCode definitions from Settings.h to HAPConstants.h. There was no reason to have the user return a StatusCode of OK or UNABLE from update() since the only other choice was BUSY and HomeKit does not seem to distinguish errors. Either it's okay or not okay, which can more easily be represented by a simply return of TRUE or FALSE from update().
The user now needs to know nothing about StatusCodes. All Examples were modified to change StatusCode update() to boolean update() and return(StatusCode:OK) to return (true).
Much simpler.
Convention is that every *.cpp references, in this order:
1) Any required core librries
2) Its own *.h (i.e. Foo.cpp -> Foo.h)
3) All other *.h files needed by the cpp, UNLESS those *.h files are already in its own *.h file. Must include all *.h files that are not in its own *.h file even if it is others that are referenced.
This change allows the user to set the log-level with homeSpan.setLogLevel() instead of needing to change in Settings.h. Next up: Update Example that introduces VERBOSE to instead use setLogLevel(). Consider adding an interactive 'L' command to change this during run-time.
Also, added "#pragma once" to every *.h file to prevent duplication of definitions. TO DO: Review all #include to ensure sanity across all files.
These optional methods can be "chained" when instantiating a new SpanService to configure the Service as Primary or Hidden (or both). This alleviates the need to ServiceType to be propogated through the Service constructor.
Next Up: Eliminate ServiceType construct and update Examples to use setPrimary instead.
Created separate init() methods for PushButton and Blinker. Created HomeSpan:setControlPin and HomeSpan:setStatusPin that can be called from main setup() to modify the defaults. All default settings being migrated to Settings.h
Next Up: Add method to break out of WiFi connection loop by using push button in case WiFi SSID/PWD has changed but there is no desire to unpair controllers. To Do: Move blinking status light setting to named macros.
Setup Code now saved after serialConfig() or apConfig().
Next up: Create 'U' command to unpair controller. Change function of control button so it unpairs (short press) or resets WiFi (long press).
To do: Revisit statusLED blinking paterns to make sure they are clear and consistent - save them as macros in settings.h
Verified all functionality works as expected. Next Up: Add this code to both serial and AP network configurations. To Do: alter 'H' command so it removes controllers (unpairs) but retains HAP ID and other data. - perhaps make this 'U' command?
This generates an SRP verification code from a setupCode and randomly-generated salt. Function creates the salt internally and returns both the resulting verification code and salt that was used. These are stored in NVS permanently.
Next Step: create SRP6A:loadVerifycode()
Move all configuration code into Network.cpp, eliminating any calls or connection to HAP.cpp. Network.cpp is now standalone for HomeSpan.cpp to call directly to handle ALL apects of WiFI and Setup Code initialization.
Also move TempBuffer from HAP.h to Utils.h so it can be used by Network.h
Allows for reset of HAP (press for 5 seconds, but less than 10) or Factory reset (press for 10 second). Use setResetPin to change from default of pint 21.
This is no longer needed since PushButtons can be easily emulated from within a Service loop() as per Example 14. Library is now fully up-to-date: TimedResets and SpanEvents have been fully removed.
Completed new framework for using loop() methods and deleted all code related to new SpanEvent() and event() loops. Re-worked Example 13 to utilize new framework and validated it functions as expected.
Service loops() called for only those Services with over-ridden loop() methods. TO DO: update event logic to follow new framework. Vector should point to all CHARACTERISTICS that are updated to setVal()
This check all timed write PID/TTL entries and clears all those that are expired. This completes the implementation of Timed Write functionality as required for PUT /prepare requests.
creating code to allow for multiple characteristics to be updated within event() call. To Do: define anogther sensor that supports multiple characteristics. also need to check that "new SpanEvent" works as expected from within a defined service.
putCharacteristics and checkNotifications now both call the same eventNotify routing. This is being done to prepare for services that will stream notifications back to client (like a temperature sensor, or pushbutton). TO DO: rename checkNotifications to check TimedResets, and rename SpanPut to something more generic.
Allow for any characteristic that is not read-only, which should leave out all string characteristics.
Upon reset, zero out all 8 bytes of UVal memory, instead of simply setting UVal.BOOL to false. This allows use of TimedReset for any characteristic with a numerical value.
Updated SpanRange to register itself automatically to the most recent Characteristic. This is more consistent with the overall framework and no longer requires user to access the range variable directly.