Merge pull request #18 from HomeSpan/Development
Merge Development into Master for Release v1.1.3
This commit is contained in:
commit
a03adabc95
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Gregg E. Berman
|
||||
Copyright (c) 2020, 2021 Gregg E. Berman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ void setup() {
|
|||
|
||||
Serial.print("\n\nHomeSpan RF Transmitter Example\n\n");
|
||||
|
||||
RFControl rf(LED_BUILTIN); // create an instance of RFControl with signal output to the ESP32's Built-In LED
|
||||
RFControl rf(13); // create an instance of RFControl with signal output to pin 13 of the ESP32
|
||||
|
||||
rf.clear(); // clear the pulse train memory buffer
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ At startup, HomeSpan:
|
|||
|
||||
If there are any errors with how you constructed your HAP Database, HomeSpan will report them and **halt** the program.
|
||||
|
||||
Next, HomeSpan checks to see if the device has been configured with WiFi Credentials. If none are found, HomeSpan will indicate this, and then complete its initialization routine by indicating is now READY. If WiFi Credentials are found, HomeSpan will repeatedly try to connect to the specified network until it either succeeds (in which case it then completes its initialization routine by indicating it is now READY), or you cancel the process by typing `X <return>` (in which case HomeSpan erases its stored WiFi Credentials and restarts).
|
||||
Next, HomeSpan checks to see if the device has been configured with WiFi Credentials. If none are found, HomeSpan will indicate this, and then complete its initialization routine by indicating is now READY. If WiFi Credentials are found, HomeSpan repeatedly tries to connect to the specified network in the background and informs you of its progress. During this time, any of the commands below will work, including those related to re-configuring or erasing the device's WiFi Credentials.
|
||||
|
||||
### Log Levels
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ void setup() {
|
|||
|
||||
Serial.print("\n\nHomeSpan RF Transmitter Example\n\n");
|
||||
|
||||
RFControl rf(LED_BUILTIN); // create an instance of RFControl with signal output to the ESP32's Built-In LED
|
||||
RFControl rf(13); // create an instance of RFControl with signal output to pin 13 on the ESP32
|
||||
|
||||
rf.clear(); // clear the pulse train memory buffer
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ In addition to being able to configure a HomeSpan device using the [HomeSpan CLI
|
|||
1. a normally-open single-pole pushbutton to function as the HomeSpan Control Button, and
|
||||
1. an LED to function as the HomeSpan Status LED.
|
||||
|
||||
The Control Button should be installed between the HomeSpan Control Pin on the ESP32 and ground. The HomeSpan Control Pin defaults to pin 21, but can be set to any other pin during HomeSpan initializaton (see the [HomeSpan API Reference](Reference.md) for details). The LED can similarly be connected to any pin you specify, but defaults to the LED_BUILTIN pin defined for your ESP32 board, in which case you can use your board's built-in LED and avoid having to install a separate LED.
|
||||
The Control Button should be installed between the HomeSpan Control Pin on the ESP32 and ground. The HomeSpan Control Pin defaults to pin 21, but can be set to any other pin during HomeSpan initializaton (see the [HomeSpan API Reference](Reference.md) for details). The LED can similarly be connected to any pin you specify, but defaults to pin 13, which for some boards is connected to a built-in LED, thereby saving you the need to install a separate LED.
|
||||
|
||||
The use of these two components to configure a standalone HomeSpan device, including starting HomeSpan's temporary WiFi network to configure the device's WiFi Credentials and HomeKit Setup Code, are fully explained in the [HomeSpan User Guide](UserGuide.md).
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -30,7 +30,7 @@ The following **optional** `homeSpan` methods override various HomeSpan initiali
|
|||
* sets the ESP32 pin to use for the HomeSpan Control Button (default=21)
|
||||
|
||||
* `void setStatusPin(uint8_t pin)`
|
||||
* sets the ESP32 pin to use for the HomeSpan Status LED (default=LED_BUILTIN)
|
||||
* sets the ESP32 pin to use for the HomeSpan Status LED (default=13). There is also a corresponding `getStatusPin()` method that returns this pin number
|
||||
|
||||
* `void setApSSID(char *ssid)`
|
||||
* sets the SSID (network name) of the HomeSpan Setup Access Point (default="HomeSpan-Setup")
|
||||
|
|
@ -59,6 +59,7 @@ The following **optional** `homeSpan` methods override various HomeSpan initiali
|
|||
Creating an instance of this **class** adds a new HAP Accessory to the HomeSpan HAP Database.
|
||||
|
||||
* every HomeSpan sketch requires at least one Accessory
|
||||
* a sketch can contain a maximum of 41 Accessories per sketch (if exceeded, a runtime error will the thrown and the sketch will halt)
|
||||
* there are no associated methods
|
||||
* the argument *aid* is optional.
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ If you are new to HomeSpan and are configuring a new device for the first time,
|
|||
|
||||
If you are setting up an existing device that has been previously configured in some unknown fashion, you may want to first perform a [Factory Reset](#factory-reset) to start with a fresh setup.
|
||||
|
||||
And if you run into any troubles, see [Troubleshooting](#troubleshooting) for tips and tricks.
|
||||
|
||||
Enjoy!
|
||||
|
||||
## HomeSpan Device States
|
||||
|
|
@ -49,13 +47,16 @@ If the Status LED blinks twice every 3 seconds, the device is connected to a WiF
|
|||
|
||||
#### PAIRED
|
||||
|
||||
If the Status LED is steady ON, the device is connected to a local WiFi network and is paired to Apple HomeKit. A device in this state should be fully operational. If not, see [Troubleshooting](#troubleshooting) for potential resolutions to common problems.
|
||||
If the Status LED is steady ON, the device is connected to a local WiFi network and is paired to Apple HomeKit. A device in this state should be fully operational.
|
||||
|
||||
#### CONNECTING
|
||||
|
||||
If the Status LED is repeatedly flashing ON for 1 second and then OFF for 1 second, the device is actively seeking to connect to a WiFi network using the WiFi Credentials stored on the device. The device will remain in this state until HomeSpan either successfully connects to a WiFi network, or you cancel the connection process.
|
||||
If the Status LED is repeatedly flashing ON for 1 second and then OFF for 1 second, the device is actively seeking to connect to a WiFi network using the WiFi Credentials stored on the device. The device will remain in this state until:
|
||||
|
||||
* HomeSpan successfully connects to a WiFi network;
|
||||
* you modify or erase the device's WiFi Credentials and restart HomeSpan via the [Device Configuration Mode](#device-configuration-mode) below;
|
||||
* you perform a [Factory Reset](#factory-reset).
|
||||
|
||||
To cancel the connection process, press and hold the HomeSpan Control Button for 3 seconds, at which point the Status LED should begin to flash rapidly (10 times per second). Upon releasing the Control Button, HomeSpan will erase the WiFi Credentials stored and reboot the device in the **NO‑WIFI** state.
|
||||
Note that the Status LED is always active, so if the LED is completely off (not even blinking), the device is not powered!
|
||||
|
||||
## Device Configuration Mode
|
||||
|
|
@ -72,7 +73,7 @@ Within Device Configuration Mode you can choose one of five possible Actions:
|
|||
|
||||
1. *Launch HomeSpan’s temporary WiFi network*. HomeSpan’s temporary WiFi network provides a simple web interface for you to input your home network’s WiFi credentials and (optionally) create your own HomeKit Setup Code. See [Setting HomeSpan’s WiFi Credentials and Setup Code](#setting-homespans-wifi-credentials-and-setup-code) for step-by-step instructions.
|
||||
|
||||
1. Unpair the device from Apple HomeKit. Under normal operation, you control the pairing and unpairing of all HomeKit devices from the Home App on your iPhone or Mac. However, there are some circumstances in which a device may need to be manually unpaired. This is typically done by performing a full [Factory Reset](#factory-reset) of the device, but that also deletes your WiFi Credentials. This action allows you to unpair the device while preserving all other device settings. See [Troubleshooting](#troubleshooting) for details.
|
||||
1. Unpair the device from Apple HomeKit. Under normal operation, you control the pairing and unpairing of all HomeKit devices from the Home App on your iPhone or Mac. However, there are some circumstances in which a device may need to be manually unpaired. This is typically done by performing a full [Factory Reset](#factory-reset) of the device, but that also deletes your WiFi Credentials. This action allows you to unpair the device while preserving all other device settings.
|
||||
|
||||
1. *Erase stored WiFi Credentials*. This allows you delete your WiFi Credentials from the device without losing any HomeKit pairing data, after which the device can be set up with new WiFi Credentials.
|
||||
|
||||
|
|
@ -106,7 +107,7 @@ You can also force a termination of the setup process at any time by pressing an
|
|||
|
||||
## Pairing to HomeKit
|
||||
|
||||
HomeSpan devices can be paired to Apple HomeKit anytime the device is in the **READY‑TO‑PAIR** state. If the device is in the **NO‑WIFI state**, it must first be connected to your home WiFi network before it can be paired to HomeKit (see [Setting HomeSpan’s WiFi Credentials and Setup Code](#setting-homespans-wifi-credentials-and-setup-code)). If the device is already in the **PAIRED** state but it is not appearing in HomeKit, you may need to manually unpair the device so it can be re-paired (see [Troubleshooting](#troubleshooting)).
|
||||
HomeSpan devices can be paired to Apple HomeKit anytime the device is in the **READY‑TO‑PAIR** state. If the device is in the **NO‑WIFI state**, it must first be connected to your home WiFi network before it can be paired to HomeKit (see [Setting HomeSpan’s WiFi Credentials and Setup Code](#setting-homespans-wifi-credentials-and-setup-code)). If the device is already in the **PAIRED** state but it is not appearing in HomeKit, you may need to manually unpair the device so it can be re-paired.
|
||||
|
||||
To reduce the possibility that a bad actor can remotely pair with a HomeKit device and take over control, HomeKit requires the use of a device-specific Setup Code to authorize the pairing process. This unique 8-digit code is not stored on the device itself (to prevent a hacker from extracting the code), but is usually found written on a tag attached to the device. Only someone who has physical access to the tag will know the Setup Code and therefore be able to pair the device to HomeKit.
|
||||
|
||||
|
|
@ -122,7 +123,7 @@ To start the pairing process, open the Home App on your iPhone, select Add Acces
|
|||
* If you have modified the Setup Code, and have also created a scannable tag with that code, scan it now.
|
||||
* If you have modified the Setup Code but have not created a scannable tag, select the option that indicates you can’t scan your code, in which case you will be able to type it manually later in the process.
|
||||
|
||||
The Home App should next display a list of available HomeKit accessories. Select your HomeSpan device (if does not appear, exit the process and try again. See Troubleshooting for other potential solutions).
|
||||
The Home App should next display a list of available HomeKit accessories. Select your HomeSpan device (if does not appear, exit the process and try again).
|
||||
|
||||
If you’ve already scanned the Setup Code for this device from a scannable tag, the Home App will begin the pairing process. If not, it will now ask you to enter it manually.
|
||||
|
||||
|
|
@ -156,11 +157,6 @@ The box can be bigger or smaller as long as you keep the same proportions. For
|
|||
|
||||
Note that if you can’t find *Scancardium* listed as a font choice in either the *Pages* or *Keynote* font dropdown boxes, select Format → Font → Show Fonts from the menu bar of the *Pages* or *Keynote* application to bring up a list of all installed fonts where you can search for, and select, *Scancardium*.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
This section contains potential solutions to common problems.
|
||||
(coming soon)
|
||||
|
||||
---
|
||||
|
||||
[↩️](README.md) Back to the Welcome page
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -23,9 +23,9 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
new Characteristic::FirmwareRevision(version);
|
||||
identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below
|
||||
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the built-in LED
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the LED
|
||||
|
||||
pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output
|
||||
pinMode(homeSpan.getStatusPin(),OUTPUT); // make sure LED is set for output
|
||||
}
|
||||
|
||||
// How HomeKit Identifies Devices:
|
||||
|
|
@ -39,20 +39,22 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
// There are many ways to implement some form of identification. For an LED, you could blink it one or more times.
|
||||
// For a LightBulb, you can flash it on and off. For window shade, you could raise and lower it.
|
||||
// Most commerical devices don't do anything. Because HomeSpan can be used to control many different types of
|
||||
// device, below we implement a very generic routine that simply blinks the internal LED of the ESP32 the
|
||||
// number of times specified above. In principle, this code could call a user-defined routine that is different
|
||||
// for each physcially-attached device (light, shade, fan, etc), but in practice this is overkill.
|
||||
// device, below we implement a very generic routine that simply blinks the Status LED the number of times specified above.
|
||||
// In principle, this code could call a user-defined routine that is different for each physcially-attached device (light, shade, fan, etc),
|
||||
// but in practice this is overkill.
|
||||
|
||||
// Note that the blink routine below starts by turning off the built-in LED and then leaves it on once it has blinked
|
||||
// Note that the blink routine below starts by turning off the Status LED and then leaves it on once it has blinked
|
||||
// the specified number of times. This is because when HomeSpan starts up if confirms to user that it has connected
|
||||
// to the WiFi network by turning on the built-in LED. Thus we want to leave it on when blinking is completed.
|
||||
// to the WiFi network by turning on the Status LED. Thus we want to leave it on when blinking is completed.
|
||||
|
||||
// Also note we use the homeSpan.getStatusPin() method to find the pin number associated with the Status LED
|
||||
|
||||
boolean update(){
|
||||
|
||||
for(int i=0;i<nBlinks;i++){
|
||||
digitalWrite(LED_BUILTIN,LOW);
|
||||
digitalWrite(homeSpan.getStatusPin(),LOW);
|
||||
delay(250);
|
||||
digitalWrite(LED_BUILTIN,HIGH);
|
||||
digitalWrite(homeSpan.getStatusPin(),HIGH);
|
||||
delay(250);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
new Characteristic::FirmwareRevision(version);
|
||||
identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below
|
||||
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the built-in LED
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the LED
|
||||
|
||||
pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output
|
||||
pinMode(homeSpan.getStatusPin(),OUTPUT); // make sure LED is set for output
|
||||
}
|
||||
|
||||
boolean update(){
|
||||
|
||||
for(int i=0;i<nBlinks;i++){
|
||||
digitalWrite(LED_BUILTIN,LOW);
|
||||
digitalWrite(homeSpan.getStatusPin(),LOW);
|
||||
delay(250);
|
||||
digitalWrite(LED_BUILTIN,HIGH);
|
||||
digitalWrite(homeSpan.getStatusPin(),HIGH);
|
||||
delay(250);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
new Characteristic::FirmwareRevision(version);
|
||||
identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below
|
||||
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the built-in LED
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the LED
|
||||
|
||||
pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output
|
||||
pinMode(homeSpan.getStatusPin(),OUTPUT); // make sure LED is set for output
|
||||
}
|
||||
|
||||
boolean update(){
|
||||
|
||||
for(int i=0;i<nBlinks;i++){
|
||||
digitalWrite(LED_BUILTIN,LOW);
|
||||
digitalWrite(homeSpan.getStatusPin(),LOW);
|
||||
delay(250);
|
||||
digitalWrite(LED_BUILTIN,HIGH);
|
||||
digitalWrite(homeSpan.getStatusPin(),HIGH);
|
||||
delay(250);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
new Characteristic::FirmwareRevision(version);
|
||||
identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below
|
||||
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the built-in LED
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the LED
|
||||
|
||||
pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output
|
||||
pinMode(homeSpan.getStatusPin(),OUTPUT); // make sure LED is set for output
|
||||
}
|
||||
|
||||
boolean update(){
|
||||
|
||||
for(int i=0;i<nBlinks;i++){
|
||||
digitalWrite(LED_BUILTIN,LOW);
|
||||
digitalWrite(homeSpan.getStatusPin(),LOW);
|
||||
delay(250);
|
||||
digitalWrite(LED_BUILTIN,HIGH);
|
||||
digitalWrite(homeSpan.getStatusPin(),HIGH);
|
||||
delay(250);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
new Characteristic::FirmwareRevision(version);
|
||||
identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below
|
||||
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the built-in LED
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the LED
|
||||
|
||||
pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output
|
||||
pinMode(homeSpan.getStatusPin(),OUTPUT); // make sure LED is set for output
|
||||
}
|
||||
|
||||
boolean update(){
|
||||
|
||||
for(int i=0;i<nBlinks;i++){
|
||||
digitalWrite(LED_BUILTIN,LOW);
|
||||
digitalWrite(homeSpan.getStatusPin(),LOW);
|
||||
delay(250);
|
||||
digitalWrite(LED_BUILTIN,HIGH);
|
||||
digitalWrite(homeSpan.getStatusPin(),HIGH);
|
||||
delay(250);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
int nBlinks; // number of times to blink built-in LED in identify routine
|
||||
SpanCharacteristic *identify; // reference to the Identify Characteristic
|
||||
|
||||
// NEW! modified constructor() method to include optional ServiceType argument
|
||||
|
||||
DEV_Identify(const char *name, const char *manu, const char *sn, const char *model, const char *version, int nBlinks) : Service::AccessoryInformation(){
|
||||
|
||||
new Characteristic::Name(name); // create all the required Characteristics with values set based on above arguments
|
||||
|
|
@ -19,17 +17,17 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
new Characteristic::FirmwareRevision(version);
|
||||
identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below
|
||||
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the built-in LED
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the LED
|
||||
|
||||
pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output
|
||||
pinMode(homeSpan.getStatusPin(),OUTPUT); // make sure LED is set for output
|
||||
}
|
||||
|
||||
boolean update(){
|
||||
|
||||
for(int i=0;i<nBlinks;i++){
|
||||
digitalWrite(LED_BUILTIN,LOW);
|
||||
digitalWrite(homeSpan.getStatusPin(),LOW);
|
||||
delay(250);
|
||||
digitalWrite(LED_BUILTIN,HIGH);
|
||||
digitalWrite(homeSpan.getStatusPin(),HIGH);
|
||||
delay(250);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
int nBlinks; // number of times to blink built-in LED in identify routine
|
||||
SpanCharacteristic *identify; // reference to the Identify Characteristic
|
||||
|
||||
// NEW! modified constructor() method to include optional ServiceType argument
|
||||
|
||||
DEV_Identify(const char *name, const char *manu, const char *sn, const char *model, const char *version, int nBlinks) : Service::AccessoryInformation(){
|
||||
|
||||
new Characteristic::Name(name); // create all the required Characteristics with values set based on above arguments
|
||||
|
|
@ -19,17 +17,17 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
new Characteristic::FirmwareRevision(version);
|
||||
identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below
|
||||
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the built-in LED
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the LED
|
||||
|
||||
pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output
|
||||
pinMode(homeSpan.getStatusPin(),OUTPUT); // make sure LED is set for output
|
||||
}
|
||||
|
||||
boolean update(){
|
||||
|
||||
for(int i=0;i<nBlinks;i++){
|
||||
digitalWrite(LED_BUILTIN,LOW);
|
||||
digitalWrite(homeSpan.getStatusPin(),LOW);
|
||||
delay(250);
|
||||
digitalWrite(LED_BUILTIN,HIGH);
|
||||
digitalWrite(homeSpan.getStatusPin(),HIGH);
|
||||
delay(250);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
new Characteristic::FirmwareRevision(version);
|
||||
identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below
|
||||
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the built-in LED
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the LED
|
||||
|
||||
pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output
|
||||
pinMode(homeSpan.getStatusPin(),OUTPUT); // make sure LED is set for output
|
||||
}
|
||||
|
||||
boolean update(){
|
||||
|
||||
for(int i=0;i<nBlinks;i++){
|
||||
digitalWrite(LED_BUILTIN,LOW);
|
||||
digitalWrite(homeSpan.getStatusPin(),LOW);
|
||||
delay(250);
|
||||
digitalWrite(LED_BUILTIN,HIGH);
|
||||
digitalWrite(homeSpan.getStatusPin(),HIGH);
|
||||
delay(250);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
new Characteristic::FirmwareRevision(version);
|
||||
identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below
|
||||
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the built-in LED
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the LED
|
||||
|
||||
pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output
|
||||
pinMode(homeSpan.getStatusPin(),OUTPUT); // make sure LED is set for output
|
||||
}
|
||||
|
||||
boolean update(){
|
||||
|
||||
for(int i=0;i<nBlinks;i++){
|
||||
digitalWrite(LED_BUILTIN,LOW);
|
||||
digitalWrite(homeSpan.getStatusPin(),LOW);
|
||||
delay(250);
|
||||
digitalWrite(LED_BUILTIN,HIGH);
|
||||
digitalWrite(homeSpan.getStatusPin(),HIGH);
|
||||
delay(250);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ struct DEV_Identify : Service::AccessoryInformation {
|
|||
new Characteristic::FirmwareRevision(version);
|
||||
identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below
|
||||
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the built-in LED
|
||||
this->nBlinks=nBlinks; // store the number of times to blink the LED
|
||||
|
||||
pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output
|
||||
pinMode(homeSpan.getStatusPin(),OUTPUT); // make sure LED is set for output
|
||||
}
|
||||
|
||||
boolean update(){
|
||||
|
||||
for(int i=0;i<nBlinks;i++){
|
||||
digitalWrite(LED_BUILTIN,LOW);
|
||||
digitalWrite(homeSpan.getStatusPin(),LOW);
|
||||
delay(250);
|
||||
digitalWrite(LED_BUILTIN,HIGH);
|
||||
digitalWrite(homeSpan.getStatusPin(),HIGH);
|
||||
delay(250);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
name=HomeSpan
|
||||
version=1.1.2
|
||||
version=1.1.3
|
||||
author=Gregg <homespan@icloud.com>
|
||||
maintainer=Gregg <homespan@icloud.com>
|
||||
sentence=A robust and extremely easy-to-use HomeKit implementation for the Espressif ESP32 running on the Arduino IDE.
|
||||
|
|
|
|||
22
src/HAP.cpp
22
src/HAP.cpp
|
|
@ -1381,10 +1381,18 @@ void HAPClient::sendEncrypted(char *body, uint8_t *dataBuf, int dataLen){
|
|||
int count=0;
|
||||
unsigned long long nBytes;
|
||||
|
||||
httpBuf[count]=bodyLen%256; // store number of bytes in first frame that encrypts the Body (AAD bytes)
|
||||
httpBuf[count+1]=bodyLen/256;
|
||||
int totalBytes=2+bodyLen+16; // 2-byte AAD + bodyLen + 16-byte authentication tag
|
||||
totalBytes+=(dataLen/FRAME_SIZE)*(2+FRAME_SIZE+16); // number of full frames * size of full frame with 2-byte AAD + 16-byte authentication tag
|
||||
|
||||
crypto_aead_chacha20poly1305_ietf_encrypt(httpBuf+count+2,&nBytes,(uint8_t *)body,bodyLen,httpBuf+count,2,NULL,a2cNonce.get(),a2cKey); // encrypt the Body with authentication tag appended
|
||||
if(dataLen%FRAME_SIZE) // if there is a residual last partial frame
|
||||
totalBytes+=2+dataLen%FRAME_SIZE+16; // 2-byte AAD + residual of last partial frame + 16-byte authentication tag
|
||||
|
||||
TempBuffer <uint8_t> tBuf(totalBytes);
|
||||
|
||||
tBuf.buf[count]=bodyLen%256; // store number of bytes in first frame that encrypts the Body (AAD bytes)
|
||||
tBuf.buf[count+1]=bodyLen/256;
|
||||
|
||||
crypto_aead_chacha20poly1305_ietf_encrypt(tBuf.buf+count+2,&nBytes,(uint8_t *)body,bodyLen,tBuf.buf+count,2,NULL,a2cNonce.get(),a2cKey); // encrypt the Body with authentication tag appended
|
||||
|
||||
a2cNonce.inc(); // increment nonce
|
||||
|
||||
|
|
@ -1397,17 +1405,17 @@ void HAPClient::sendEncrypted(char *body, uint8_t *dataBuf, int dataLen){
|
|||
if(n>FRAME_SIZE) // maximum number of bytes to encrypt=FRAME_SIZE
|
||||
n=FRAME_SIZE;
|
||||
|
||||
httpBuf[count]=n%256; // store number of bytes that encrypts this frame (AAD bytes)
|
||||
httpBuf[count+1]=n/256;
|
||||
tBuf.buf[count]=n%256; // store number of bytes that encrypts this frame (AAD bytes)
|
||||
tBuf.buf[count+1]=n/256;
|
||||
|
||||
crypto_aead_chacha20poly1305_ietf_encrypt(httpBuf+count+2,&nBytes,dataBuf+i,n,httpBuf+count,2,NULL,a2cNonce.get(),a2cKey); // encrypt the next portion of dataBuf with authentication tag appended
|
||||
crypto_aead_chacha20poly1305_ietf_encrypt(tBuf.buf+count+2,&nBytes,dataBuf+i,n,tBuf.buf+count,2,NULL,a2cNonce.get(),a2cKey); // encrypt the next portion of dataBuf with authentication tag appended
|
||||
|
||||
a2cNonce.inc(); // increment nonce
|
||||
|
||||
count+=2+n+16; // increment count by 2-byte AAD record + length of JSON + 16-byte authentication tag
|
||||
}
|
||||
|
||||
client.write(httpBuf,count); // transmit all encrypted frames to Client
|
||||
client.write(tBuf.buf,count); // transmit all encrypted frames to Client
|
||||
|
||||
LOG2("-------- SENT ENCRYPTED! --------\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ struct HAPClient {
|
|||
|
||||
static const int MAX_HTTP=8095; // max number of bytes in HTTP message buffer
|
||||
static const int MAX_CONTROLLERS=16; // maximum number of paired controllers (HAP requires at least 16)
|
||||
static const int MAX_ACCESSORIES=41; // maximum number of allowed Acessories (HAP limit=150, but not enough memory in ESP32 to run that many)
|
||||
|
||||
static TLV<kTLVType,10> tlv8; // TLV8 structure (HAP Section 14.1) with space for 10 TLV records of type kTLVType (HAP Table 5-6)
|
||||
static nvs_handle hapNVS; // handle for non-volatile-storage of HAP data
|
||||
|
|
|
|||
121
src/HomeSpan.cpp
121
src/HomeSpan.cpp
|
|
@ -67,7 +67,7 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa
|
|||
"** Please ensure serial monitor is set to transmit <newlines>\n\n");
|
||||
|
||||
Serial.print("Message Logs: Level ");
|
||||
Serial.print(homeSpan.logLevel);
|
||||
Serial.print(logLevel);
|
||||
Serial.print("\nStatus LED: Pin ");
|
||||
Serial.print(statusPin);
|
||||
Serial.print("\nDevice Control: Pin ");
|
||||
|
|
@ -82,7 +82,7 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa
|
|||
Serial.print(__TIME__);
|
||||
|
||||
Serial.print("\n\nDevice Name: ");
|
||||
Serial.print(homeSpan.displayName);
|
||||
Serial.print(displayName);
|
||||
Serial.print("\n\n");
|
||||
|
||||
} // begin
|
||||
|
|
@ -122,11 +122,11 @@ void Span::poll() {
|
|||
|
||||
HAPClient::init(); // read NVS and load HAP settings
|
||||
|
||||
if(strlen(network.wifiData.ssid)>0){
|
||||
initWifi();
|
||||
} else {
|
||||
Serial.print("*** WIFI CREDENTIALS DATA NOT FOUND -- PLEASE CONFIGURE BY TYPING 'W <RETURN>' OR PRESS CONTROL BUTTON FOR 3 SECONDS TO START ACCESS POINT.\n\n");
|
||||
if(!strlen(network.wifiData.ssid)){
|
||||
Serial.print("*** WIFI CREDENTIALS DATA NOT FOUND. YOU MAY CONFIGURE BY TYPING 'W <RETURN>'.\n\n");
|
||||
statusLED.start(LED_WIFI_NEEDED);
|
||||
} else {
|
||||
homeSpan.statusLED.start(LED_WIFI_CONNECTING);
|
||||
}
|
||||
|
||||
controlButton.reset();
|
||||
|
|
@ -137,8 +137,8 @@ void Span::poll() {
|
|||
|
||||
} // isInitialized
|
||||
|
||||
if(strlen(network.wifiData.ssid)>0 && WiFi.status()!=WL_CONNECTED){
|
||||
initWifi();
|
||||
if(strlen(network.wifiData.ssid)>0){
|
||||
checkConnect();
|
||||
}
|
||||
|
||||
char cBuf[17]="?";
|
||||
|
|
@ -308,7 +308,54 @@ void Span::commandMode(){
|
|||
|
||||
//////////////////////////////////////
|
||||
|
||||
void Span::initWifi(){
|
||||
void Span::checkConnect(){
|
||||
|
||||
if(connected){
|
||||
if(WiFi.status()==WL_CONNECTED)
|
||||
return;
|
||||
|
||||
Serial.print("\n\n*** WiFi Connection Lost!\n"); // losing and re-establishing connection has not been tested
|
||||
connected=false;
|
||||
waitTime=60000;
|
||||
alarmConnect=0;
|
||||
homeSpan.statusLED.start(LED_WIFI_CONNECTING);
|
||||
}
|
||||
|
||||
if(WiFi.status()!=WL_CONNECTED){
|
||||
if(millis()<alarmConnect) // not yet time to try to try connecting
|
||||
return;
|
||||
|
||||
if(waitTime==60000)
|
||||
waitTime=1000;
|
||||
else
|
||||
waitTime*=2;
|
||||
|
||||
if(waitTime==32000){
|
||||
Serial.print("\n*** Can't connect to ");
|
||||
Serial.print(network.wifiData.ssid);
|
||||
Serial.print(". You may type 'W <return>' to re-configure WiFi, or 'X <return>' to erase WiFi credentials. Will try connecting again in 60 seconds.\n\n");
|
||||
waitTime=60000;
|
||||
} else {
|
||||
Serial.print("Trying to connect to ");
|
||||
Serial.print(network.wifiData.ssid);
|
||||
Serial.print(". Waiting ");
|
||||
Serial.print(waitTime/1000);
|
||||
Serial.print(" second(s) for response...\n");
|
||||
WiFi.begin(network.wifiData.ssid,network.wifiData.pwd);
|
||||
}
|
||||
|
||||
alarmConnect=millis()+waitTime;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
connected=true;
|
||||
|
||||
Serial.print("Successfully connected to ");
|
||||
Serial.print(network.wifiData.ssid);
|
||||
Serial.print("! IP Address: ");
|
||||
Serial.print(WiFi.localIP());
|
||||
Serial.print("\n");
|
||||
|
||||
char id[18]; // create string version of Accessory ID for MDNS broadcast
|
||||
memcpy(id,HAPClient::accessory.ID,17); // copy ID bytes
|
||||
|
|
@ -320,54 +367,6 @@ void Span::initWifi(){
|
|||
char hostName[nChars+1];
|
||||
sprintf(hostName,"%s-%.2s%.2s%.2s%.2s%.2s%.2s",hostNameBase,id,id+3,id+6,id+9,id+12,id+15);
|
||||
|
||||
statusLED.start(LED_WIFI_CONNECTING);
|
||||
controlButton.reset();
|
||||
|
||||
int nTries=0;
|
||||
|
||||
Serial.print("Attempting connection to: ");
|
||||
Serial.print(network.wifiData.ssid);
|
||||
Serial.print(". Type 'X <return>' or press Control Button for 3 seconds at any time to terminate search and delete WiFi credentials.");
|
||||
|
||||
while(WiFi.status()!=WL_CONNECTED){
|
||||
|
||||
if(nTries++ == 0)
|
||||
Serial.print("\nConnecting..");
|
||||
|
||||
if(WiFi.begin(network.wifiData.ssid,network.wifiData.pwd)!=WL_CONNECTED){
|
||||
int delayTime;
|
||||
char buf[8]="";
|
||||
if(nTries<=10){
|
||||
delayTime=2000;
|
||||
Serial.print(".");
|
||||
} else {
|
||||
nTries=0;
|
||||
delayTime=60000;
|
||||
Serial.print(" Can't connect! Will re-try in ");
|
||||
Serial.print(delayTime/1000);
|
||||
Serial.print(" seconds...");
|
||||
}
|
||||
long sTime=millis();
|
||||
|
||||
while(millis()-sTime<delayTime){
|
||||
if(controlButton.triggered(9999,3000)){
|
||||
Serial.print(" TERMINATED!\n");
|
||||
statusLED.start(LED_ALERT);
|
||||
controlButton.wait();
|
||||
processSerialCommand("X"); // DELETE WiFi Data and Restart
|
||||
}
|
||||
if (Serial.available() && readSerial(buf,1) && (buf[0]=='X')){
|
||||
Serial.print(" TERMINATED!\n");
|
||||
processSerialCommand("X"); // DELETE WiFi Data and Restart
|
||||
}
|
||||
}
|
||||
}
|
||||
} // WiFi not yet connected
|
||||
|
||||
Serial.print(" Success!\nIP: ");
|
||||
Serial.print(WiFi.localIP());
|
||||
Serial.print("\n");
|
||||
|
||||
Serial.print("\nStarting MDNS...\n");
|
||||
Serial.print("Broadcasting as: ");
|
||||
Serial.print(hostName);
|
||||
|
|
@ -1062,6 +1061,14 @@ int Span::sprintfAttributes(char **ids, int numIDs, int flags, char *cBuf){
|
|||
SpanAccessory::SpanAccessory(uint32_t aid){
|
||||
|
||||
if(!homeSpan.Accessories.empty()){
|
||||
|
||||
if(homeSpan.Accessories.size()==HAPClient::MAX_ACCESSORIES){
|
||||
Serial.print("\n\n*** FATAL ERROR: Can't create more than ");
|
||||
Serial.print(HAPClient::MAX_ACCESSORIES);
|
||||
Serial.print(" Accessories. Program Halting.\n\n");
|
||||
while(1);
|
||||
}
|
||||
|
||||
this->aid=homeSpan.Accessories.back()->aid+1;
|
||||
|
||||
if(!homeSpan.Accessories.back()->Services.empty())
|
||||
|
|
|
|||
|
|
@ -85,6 +85,10 @@ struct Span{
|
|||
String configLog; // log of configuration process, including any errors
|
||||
boolean isBridge=true; // flag indicating whether device is configured as a bridge (i.e. first Accessory contains nothing but AccessoryInformation and HAPProtocolInformation)
|
||||
|
||||
boolean connected=false; // WiFi connection status
|
||||
unsigned long waitTime=60000; // time to wait (in milliseconds) between WiFi connection attempts
|
||||
unsigned long alarmConnect=0; // time after which WiFi connection attempt should be tried again
|
||||
|
||||
const char *defaultSetupCode=DEFAULT_SETUP_CODE; // Setup Code used for pairing
|
||||
uint8_t statusPin=DEFAULT_STATUS_PIN; // pin for status LED
|
||||
uint8_t controlPin=DEFAULT_CONTROL_PIN; // pin for Control Pushbutton
|
||||
|
|
@ -112,7 +116,7 @@ struct Span{
|
|||
|
||||
void poll(); // poll HAP Clients and process any new HAP requests
|
||||
int getFreeSlot(); // returns free HAPClient slot number. HAPClients slot keep track of each active HAPClient connection
|
||||
void initWifi(); // initialize and connect to WiFi network
|
||||
void checkConnect(); // check WiFi connection; connect if needed
|
||||
void commandMode(); // allows user to control and reset HomeSpan settings with the control button
|
||||
void processSerialCommand(const char *c); // process command 'c' (typically from readSerial, though can be called with any 'c')
|
||||
|
||||
|
|
@ -130,6 +134,7 @@ struct Span{
|
|||
|
||||
void setControlPin(uint8_t pin){controlPin=pin;} // sets Control Pin
|
||||
void setStatusPin(uint8_t pin){statusPin=pin;} // sets Status Pin
|
||||
int getStatusPin(){return(statusPin);} // gets Status Pin
|
||||
void setApSSID(char *ssid){network.apSSID=ssid;} // sets Access Point SSID
|
||||
void setApPassword(char *pwd){network.apPassword=pwd;} // sets Access Point Password
|
||||
void setApTimeout(uint16_t nSec){network.lifetime=nSec*1000;} // sets Access Point Timeout (seconds)
|
||||
|
|
|
|||
|
|
@ -273,12 +273,13 @@ void Network::processRequest(char *body, char *formData){
|
|||
getFormValue(formData,"network",wifiData.ssid,MAX_SSID);
|
||||
getFormValue(formData,"pwd",wifiData.pwd,MAX_PWD);
|
||||
|
||||
timer=millis();
|
||||
homeSpan.statusLED.start(LED_WIFI_CONNECTING);
|
||||
|
||||
responseBody+="<meta http-equiv = \"refresh\" content = \"2; url = /wifi-status\" />"
|
||||
responseBody+="<meta http-equiv = \"refresh\" content = \"" + String(waitTime) + "; url = /wifi-status\" />"
|
||||
"<p>Initiating WiFi connection to:</p><p><b>" + String(wifiData.ssid) + "</p>";
|
||||
|
||||
WiFi.begin(wifiData.ssid,wifiData.pwd);
|
||||
|
||||
} else
|
||||
|
||||
if(!strncmp(body,"POST /save ",11)){ // GET SAVE
|
||||
|
|
@ -306,12 +307,17 @@ void Network::processRequest(char *body, char *formData){
|
|||
|
||||
LOG1("In Get WiFi Status...\n");
|
||||
|
||||
if(WiFi.status()!=WL_CONNECTED && WiFi.begin(wifiData.ssid,wifiData.pwd)!=WL_CONNECTED){
|
||||
responseHead+="Refresh: 5\r\n";
|
||||
|
||||
responseBody+="<p>Re-trying connection to:</p><p><b>" + String(wifiData.ssid) + "</p>";
|
||||
responseBody+="<p>Timeout in " + String((alarmTimeOut-millis())/1000) + " seconds.</p>";
|
||||
if(WiFi.status()!=WL_CONNECTED){
|
||||
waitTime+=2;
|
||||
if(waitTime==12)
|
||||
waitTime=2;
|
||||
responseHead+="Refresh: " + String(waitTime) + "\r\n";
|
||||
responseBody+="<p>Re-initiating connection to:</p><p><b>" + String(wifiData.ssid) + "</b></p>";
|
||||
responseBody+="<p>(waiting " + String(waitTime) + " seconds to check for response)</p>";
|
||||
responseBody+="<p>Access Point termination in " + String((alarmTimeOut-millis())/1000) + " seconds.</p>";
|
||||
responseBody+="<center><button onclick=\"document.location='/hotspot-detect.html'\">Cancel</button></center>";
|
||||
WiFi.begin(wifiData.ssid,wifiData.pwd);
|
||||
|
||||
} else {
|
||||
|
||||
homeSpan.statusLED.start(LED_AP_CONNECTED); // slow double-blink
|
||||
|
|
@ -335,6 +341,7 @@ void Network::processRequest(char *body, char *formData){
|
|||
LOG1("In Landing Page...\n");
|
||||
|
||||
homeSpan.statusLED.start(LED_AP_CONNECTED);
|
||||
waitTime=2;
|
||||
|
||||
responseBody+="<p>Welcome to HomeSpan! This page allows you to configure the above HomeSpan device to connect to your WiFi network.</p>"
|
||||
"<p>The LED on this device should be <em>double-blinking</em> during this configuration.</p>"
|
||||
|
|
@ -391,8 +398,14 @@ int Network::getFormValue(char *formData, const char *tag, char *value, int maxS
|
|||
int len=0; // track length of value
|
||||
|
||||
while(*v!='\0' && *v!='&' && len<maxSize){ // copy the value until null, '&', or maxSize is reached
|
||||
if(*v=='%'){ // this is an escaped character of form %XX
|
||||
v++;
|
||||
sscanf(v,"%2x",value++);
|
||||
v+=2;
|
||||
} else {
|
||||
*value++=*v++;
|
||||
}
|
||||
len++;
|
||||
*value++=*v++;
|
||||
}
|
||||
|
||||
*value='\0'; // add terminating null
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ struct Network {
|
|||
int numSSID;
|
||||
|
||||
WiFiClient client; // client used for HTTP calls
|
||||
unsigned long timer; // length of time of trying to connect to WiFi
|
||||
int waitTime; // time to wait between HTTP refreshed when checking for WiFi connection
|
||||
unsigned long alarmTimeOut; // alarm time after which access point is shut down and HomeSpan is re-started
|
||||
int apStatus; // tracks access point status (0=timed-out, -1=cancel, 1=save)
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
#define HS_MAJOR 1
|
||||
#define HS_MINOR 1
|
||||
#define HS_PATCH 2
|
||||
#define HS_PATCH 3
|
||||
|
||||
#define STRINGIFY(x) _STR(x)
|
||||
#define _STR(x) #x
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
#define DEFAULT_SETUP_CODE "46637726" // changed during network setup or with 'S' command
|
||||
|
||||
#define DEFAULT_CONTROL_PIN 21 // change with homeSpan.setControlPin(pin)
|
||||
#define DEFAULT_STATUS_PIN LED_BUILTIN // change with homeSpan.setStatusPin(pin)
|
||||
#define DEFAULT_STATUS_PIN 13 // change with homeSpan.setStatusPin(pin)
|
||||
|
||||
#define DEFAULT_AP_SSID "HomeSpan-Setup" // change with homeSpan.setApSSID(pwd)
|
||||
#define DEFAULT_AP_PASSWORD "homespan" // change with homeSpan.setApPassword(pwd)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@ struct TempBuffer {
|
|||
TempBuffer(size_t len){
|
||||
nBytes=len*sizeof(bufType);
|
||||
buf=(bufType *)heap_caps_malloc(nBytes,MALLOC_CAP_8BIT);
|
||||
if(buf==NULL){
|
||||
Serial.print("\n\n*** FATAL ERROR: Requested allocation of ");
|
||||
Serial.print(nBytes);
|
||||
Serial.print(" bytes failed. Program Halting.\n\n");
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
|
||||
~TempBuffer(){
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ void setup() {
|
|||
|
||||
homeSpan.setLogLevel(2);
|
||||
|
||||
homeSpan.begin();
|
||||
homeSpan.begin(Category::Lighting,"HomeSpanTest");
|
||||
|
||||
new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), which takes no arguments
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue