diff --git a/.gitmodules b/.gitmodules
index d3d8014..dfaaa35 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,15 @@
[submodule "main/libraries/variant"]
path = main/libraries/variant
url = https://github.com/mpark/variant.git
+[submodule "components/homekit"]
+ path = components/homekit
+ url = https://github.com/sieren/esp-homekit.git
+[submodule "components/http-parser"]
+ path = components/http-parser
+ url = https://github.com/sieren/esp-http-parser.git
+[submodule "components/wolfssl"]
+ path = components/wolfssl
+ url = https://github.com/sieren/esp-wolfssl.git
+[submodule "components/cJSON"]
+ path = components/cJSON
+ url = https://github.com/sieren/esp-cjson.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fa9a478..8824391 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,4 +11,10 @@ list(APPEND compile_definitions "ARDUINO=202000")
# pending PR: https://github.com/VSChina/ESP32_AzureIoT_Arduino/pull/15
list(APPEND compile_options "-Wno-maybe-uninitialized")
+set(EXTRA_COMPONENT_DIRS
+"components/esp-wolfssl/"
+"components/http-parser"
+)
+
+
project(homepoint)
diff --git a/README.md b/README.md
index 437d1bc..9f942c0 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
Homepoint
=============
-#### An ESP32 based Smarthome Controller for MQTT
+#### An ESP32 based Smarthome Controller for MQTT & HomeKit

@@ -8,8 +8,11 @@ Status")
"Issues")](https://github.com/sieren/Homepoint/issues)
Homepoint is a screen-based interface for MQTT-connected Smarthome devices that runs
-on the cheaply available ESP32 Chipset.
-This project requires a MQTT-Broker to be running in your smarthome.
+on the cheaply available ESP32 Chipset.
+It can also provide *Switches* to *HomeKit*. These can be used inside the Home App on iOS
+to trigger other HomeKit Devices.
+
+For MQTT this project requires a MQTT-Broker to be running in your smarthome.

[](https://www.youtube.com/watch?v=bqzpkvtQSvY "HomePoint Youtube demo")
@@ -21,14 +24,17 @@ This project requires a MQTT-Broker to be running in your smarthome.
+ Trigger individual devices by diving into scenes (by tapping the indicator or long pressing a button).
+ See partially switched on scenes with multiple devices at a glance.
+ Support for temperature, humidity and air quality sensors.
++ HomeKit Switch Support (Setup Automations in Home App to toggle from Homepoint)
+ Supports both Touch Screen or Button based navigation.
+ Screen updates automatically when devices are triggered from elsewhere.
+ Easy configuration through a JSON files.
+ Screensaver saves power by switching off screen after 10 minutes.
+ Statusbar shows connectivity for WiFi and MQTT as well as time.
+
#### Planned
-+ HomeKit Button/Switch Support (for users without MQTT to setup Automations they can toggle from Homepoint)
+
++ Improve HomeKit Support
+ Improved documentation
Is there a feature missing? Open an issue, send me an [email](mailto:info@s-r-n.de) or fork this project and add it yourself.
@@ -134,3 +140,28 @@ Homepoint gets its time from an NTP Server. In order to set the correct timezone
```
Switches can have custom icons, the icons of sensors are currently fixed and not customizable.
See the `data` folder for available icons or add your own following the naming scheme visible there.
+
+### HomeKit
+To active *HomeKit*, simply set a PIN in the configuration file.
+Beware that the PIN has to follow the scheme of `xxx-xx-xxx`.
+A single HomeKit Switch is of `type: "HomeKitSwitch"`.
+It may not contain any devices.
+
+```
+{
+ "wifi": "MyWifiSSID",
+ "password": "My Wifi Password",
+ "mqttbroker": "mqtt://192.168.1.2",
+ "mqttusername": "mqttusername",
+ "mqttpasswd": "mymqttpassword",
+ "homekitpin": "111-11-111",
+ "timezone": "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00",
+ "scenes": [
+ {
+ "name": "Living Room",
+ "type": "HomeKitSwitch",
+ "icon": "livingroom"
+ }]
+}
+```
+
diff --git a/components/cJSON b/components/cJSON
new file mode 160000
index 0000000..2b93171
--- /dev/null
+++ b/components/cJSON
@@ -0,0 +1 @@
+Subproject commit 2b9317101a7ffbcf834eaebf7ef92b6d52d10ff4
diff --git a/components/homekit b/components/homekit
new file mode 160000
index 0000000..6cde4f9
--- /dev/null
+++ b/components/homekit
@@ -0,0 +1 @@
+Subproject commit 6cde4f96d647fce1baf5e0e81902da0ce0fdcfb7
diff --git a/components/http-parser b/components/http-parser
new file mode 160000
index 0000000..dc9b2cb
--- /dev/null
+++ b/components/http-parser
@@ -0,0 +1 @@
+Subproject commit dc9b2cb0c8d397dc3bbad20f398828cefb45e8b5
diff --git a/components/wolfssl b/components/wolfssl
new file mode 160000
index 0000000..04de416
--- /dev/null
+++ b/components/wolfssl
@@ -0,0 +1 @@
+Subproject commit 04de416bd7642c1f9053caa3e3022c84053e892a
diff --git a/data/config.json b/data/config.json
index f0e3863..f241979 100644
--- a/data/config.json
+++ b/data/config.json
@@ -4,8 +4,14 @@
"mqttbroker": "mqtt://192.168.1.1",
"mqttusername": "myusername",
"mqttpasswd": "mypassword",
+ "homekitpin": "111-11-111",
"timezone": "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00",
"scenes": [
+ {
+ "name": "Entrance",
+ "type": "HomeKitSwitch",
+ "icon": "door"
+ },
{
"name": "Entrance",
"type": "Light",
diff --git a/main/AppContext.cpp b/main/AppContext.cpp
index da22234..cd8b81d 100644
--- a/main/AppContext.cpp
+++ b/main/AppContext.cpp
@@ -12,8 +12,13 @@ namespace ctx
void AppContext::setup()
{
fs::FileSystem::getInstance().loadPartitions();
- mMQTTGroups = fs::ConfigReader::getMQTTGroups();
- mpMQTTConnection = std::make_shared(fs::ConfigReader::getMQTTConfig(), mMQTTGroups);
+ mDeviceGroups = fs::ConfigReader::getDeviceGroups();
+ const auto hkConfig = fs::ConfigReader::getHKConfig();
+ if (hkConfig.isEnabled)
+ {
+ mpHKConnection = std::make_shared(hkConfig, mDeviceGroups);
+ }
+ mpMQTTConnection = std::make_shared(fs::ConfigReader::getMQTTConfig(), mDeviceGroups);
const auto timeZone = fs::ConfigReader::getTimeZone();
if (timeZone != "")
{
@@ -34,12 +39,16 @@ namespace ctx
if (cb == mqtt::MQTTConnectionStatus::CONNECTED)
{
mpMQTTConnection->bindScenes();
+ if (mpHKConnection)
+ {
+ mpHKConnection->start();
+ }
}
});
}
- std::vector &AppContext::getMQTTGroups()
+ std::vector &AppContext::getDeviceGroups()
{
- return mMQTTGroups;
+ return mDeviceGroups;
}
} // namespace ctx
diff --git a/main/AppContext.h b/main/AppContext.h
index f8b4c7b..3e2c1b6 100644
--- a/main/AppContext.h
+++ b/main/AppContext.h
@@ -1,5 +1,6 @@
#pragma once
+#include
#include
#include
#include
@@ -21,13 +22,14 @@ namespace ctx
WifiContext& getWifiContext() { return mWifiContext; };
std::shared_ptr getMQTTConnection() { return mpMQTTConnection; };
- std::vector &getMQTTGroups();
+ std::vector &getDeviceGroups();
private:
std::shared_ptr mpMQTTConnection;
+ std::shared_ptr mpHKConnection = nullptr;
std::shared_ptr mNTPSync;
WifiContext mWifiContext;
- std::vector mMQTTGroups;
+ std::vector mDeviceGroups;
rapidjson::Document mConfigDocument;
};
} // namespace ctx
diff --git a/main/AppScreen.ipp b/main/AppScreen.ipp
index 53b16b3..9e7b092 100644
--- a/main/AppScreen.ipp
+++ b/main/AppScreen.ipp
@@ -42,7 +42,7 @@ namespace gfx
template
void AppScreen::presentScreen(const uint16_t sceneId)
{
- auto& scenes = mpAppContext->getMQTTGroups();
+ auto& scenes = mpAppContext->getDeviceGroups();
auto widgets = std::vector();
auto mqttScene = std::find_if(scenes.begin(), scenes.end(), [&](auto& scene)
@@ -110,7 +110,7 @@ namespace gfx
void AppScreen::presentMenu()
{
auto screenNavigator = std::make_shared>(&mTft, menuFrame, 1000);
- auto& scenes = mpAppContext->getMQTTGroups();
+ auto& scenes = mpAppContext->getDeviceGroups();
auto widgets = std::vector();
for (auto& scene : scenes)
{
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
index 2cde7c5..a4879a0 100644
--- a/main/CMakeLists.txt
+++ b/main/CMakeLists.txt
@@ -17,6 +17,14 @@ file(GLOB FS_SRC
"${FS_SRC_PATH}/Filesystem.cpp"
)
+
+set(HOMEKIT_SRC_PATH "homekit")
+file(GLOB HOMEKIT_SRC
+ "${HOMEKIT_SRC_PATH}/hkapi.c"
+ "${HOMEKIT_SRC_PATH}/HKConnection.cpp"
+)
+
+
set(MQTT_SRC_PATH "mqtt")
file(GLOB MQTT_SRC
"${MQTT_SRC_PATH}/MQTTConnection.cpp"
@@ -72,6 +80,7 @@ set(COMPONENT_SRCS
"AppContext.cpp"
"main.cpp"
${FS_SRC}
+ ${HOMEKIT_SRC}
${UI_SRC}
${MQTT_SRC}
${NTP_SRC}
diff --git a/main/devices/DeviceTypes.hpp b/main/devices/DeviceTypes.hpp
new file mode 100644
index 0000000..89266fd
--- /dev/null
+++ b/main/devices/DeviceTypes.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include
+#include
+#include "mpark/variant.hpp"
+
+using DeviceVariants = mpark::variant;
diff --git a/main/fs/ConfigReader.hpp b/main/fs/ConfigReader.hpp
index 64acdbb..1f61cfd 100644
--- a/main/fs/ConfigReader.hpp
+++ b/main/fs/ConfigReader.hpp
@@ -3,6 +3,8 @@
#include
#include "rapidjson/document.h"
#include "Filesystem.h"
+#include
+#include
#include
#include
#include
@@ -67,7 +69,24 @@ namespace fs
return conf;
}
- static std::vector getMQTTGroups()
+ static const homekit::HKConfig getHKConfig()
+ {
+ mqtt::MQTTConfig conf;
+ using namespace rapidjson;
+ auto config = fs::FileSystem::getInstance().readJsonConfig("/spiffs/config.json");
+ const char* configChar = config.c_str();
+ Document document;
+ document.Parse<0>(configChar);
+
+ if (document.HasMember("homekitpin"))
+ {
+ Value& hkPin = document["homekitpin"];
+ return homekit::HKConfig{hkPin.GetString(), true};;
+ }
+ return homekit::HKConfig{std::string(""), false};
+ }
+
+ static std::vector getDeviceGroups()
{
using namespace rapidjson;
using namespace mqtt;
@@ -78,7 +97,7 @@ namespace fs
uint16_t tagId = 0;
const auto& scenes = document["scenes"].GetArray();
- std::vector vecScenes;
+ std::vector vecScenes;
for (const auto& scene : scenes)
{
if (std::string(scene["type"].GetString()) == "Light" ||
@@ -103,9 +122,10 @@ namespace fs
}
aScene->mDevices = devices;
aScene->groupId = tagId;
- MQTTVariants variant = aScene;
+ DeviceVariants variant = aScene;
vecScenes.push_back(aScene);
}
+
else if (std::string(scene["type"].GetString()) == "Sensor")
{
auto aScene = std::make_shared();
@@ -162,7 +182,17 @@ namespace fs
}
aScene->mSensorDevices = devices;
aScene->groupId = tagId;
- MQTTVariants variant = aScene;
+ DeviceVariants variant = aScene;
+ vecScenes.push_back(aScene);
+ }
+
+ else if (std::string(scene["type"].GetString()) == "HomeKitSwitch")
+ {
+ auto aScene = std::make_shared();
+ aScene->sceneName = scene["name"].GetString();
+ aScene->iconName = scene["icon"].GetString();
+ aScene->groupId = tagId;
+ DeviceVariants variant = aScene;
vecScenes.push_back(aScene);
}
tagId += 1;
diff --git a/main/homekit/HKConfig.hpp b/main/homekit/HKConfig.hpp
new file mode 100644
index 0000000..cd4dfe7
--- /dev/null
+++ b/main/homekit/HKConfig.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include
+
+namespace homekit
+{
+ struct HKConfig
+ {
+ std::string password;
+ bool isEnabled = false;
+ };
+} // namespace homekit
diff --git a/main/homekit/HKConnection.cpp b/main/homekit/HKConnection.cpp
new file mode 100644
index 0000000..97866a3
--- /dev/null
+++ b/main/homekit/HKConnection.cpp
@@ -0,0 +1,37 @@
+#include
+#include
+#include "HKConnection.h"
+#include "HKDevice.hpp"
+
+extern "C"
+{
+ #include
+ #include
+ #include
+ #include "hkapi.h"
+}
+
+namespace homekit
+{
+
+ HKConnection::HKConnection(const HKConfig& config, const std::vector devices) :
+ mDevices(devices),
+ mConfig(config)
+ {
+ hkInitService();
+ for (auto& device : mDevices)
+ {
+ mpark::visit(::util::overloaded(
+ [&](HKDevicePtr& ptr)
+ {
+ hkAddDevice(ptr->sceneName.c_str(), ptr->characteristic);
+ },
+ [](auto&& i) {}), device);
+ }
+ }
+
+ void HKConnection::start()
+ {
+ hkInit(mConfig.password.c_str());
+ }
+} // namespace homekit
diff --git a/main/homekit/HKConnection.h b/main/homekit/HKConnection.h
new file mode 100644
index 0000000..abed39a
--- /dev/null
+++ b/main/homekit/HKConnection.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+#include "HKConfig.hpp"
+#include "HKDevice.hpp"
+#include
+
+namespace homekit
+{
+ class HKConnection
+ {
+ public:
+ HKConnection() = delete;
+ HKConnection(const HKConfig& config, const std::vector devices);
+ void start();
+
+ private:
+ std::vector mDevices;
+ const HKConfig mConfig;
+ };
+}
\ No newline at end of file
diff --git a/main/homekit/HKDevice.hpp b/main/homekit/HKDevice.hpp
new file mode 100644
index 0000000..99a9275
--- /dev/null
+++ b/main/homekit/HKDevice.hpp
@@ -0,0 +1,90 @@
+#pragma once
+
+#include
+#include
+
+extern "C"
+{
+ #include
+ #include
+ #include
+ #include
+}
+namespace homekit
+{
+ struct HKDevice;
+} // namespace homekit
+
+using HKDevicePtr = std::shared_ptr;
+namespace homekit
+{
+ struct HKDevice
+ {
+ static void deviceSetCallback(homekit_characteristic_t *ch, const homekit_value_t value)
+ {
+ (*static_cast(ch->context)).setDeviceState(value.bool_value);
+ }
+
+ void setDeviceState(bool on)
+ {
+ if (on != mIsActive)
+ {
+ homekit_value_t newValue;
+ newValue.format = homekit_format_bool;
+ newValue.bool_value = on;
+ characteristic->value = newValue;
+ mIsActive = on;
+ homekit_characteristic_notify(characteristic, characteristic->value);
+ if (mSetNeedsUpdateCB)
+ {
+ mSetNeedsUpdateCB(on);
+ }
+ }
+ }
+
+ HKDevice(const HKDevice&) =delete;
+ HKDevice& operator=(const HKDevice&) =delete;
+
+ HKDevice& operator=(HKDevice&& other)
+ {
+ characteristic = other.characteristic;
+ sceneName = other.sceneName;
+ characteristic->context = this;
+ return *this;
+ }
+
+ HKDevice(const HKDevice&& other)
+ {
+ characteristic = other.characteristic;
+ sceneName = other.sceneName;
+ characteristic->context = this;
+ }
+
+ HKDevice()
+ {
+ characteristic = new homekit_characteristic_t{};
+ characteristic->setter_ex = deviceSetCallback;
+ characteristic->context = this;
+ characteristic->type = HOMEKIT_CHARACTERISTIC_ON;
+ characteristic->description = "On";
+ characteristic->format = homekit_format_bool;
+ characteristic->permissions = static_cast(homekit_permissions_paired_read |
+ homekit_permissions_paired_write | homekit_permissions_notify);
+ homekit_value_t val;
+ val.bool_value = true;
+ characteristic->value = val;
+ }
+
+ bool isActive() const
+ {
+ return mIsActive;
+ }
+
+ std::string sceneName = "";
+ std::string iconName = "";
+ uint16_t groupId;
+ bool mIsActive = false;
+ std::function mSetNeedsUpdateCB;
+ homekit_characteristic_t* characteristic;
+ };
+} // namespace homekit
\ No newline at end of file
diff --git a/main/homekit/hkapi.c b/main/homekit/hkapi.c
new file mode 100644
index 0000000..fef49ab
--- /dev/null
+++ b/main/homekit/hkapi.c
@@ -0,0 +1,80 @@
+ #define SPIFLASH_BASE_ADDR 0x8c000
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+
+ #include
+ #include
+
+ #include
+ #include
+
+homekit_server_config_t config;
+homekit_service_t* services[10 + 1];
+homekit_service_t** s = services;
+homekit_accessory_t *accessories[10];
+
+static int currentPos = 0;
+
+void switch_identify(homekit_value_t _value) {
+ // DO NOTHING FOR NOW
+}
+
+void hkInitService()
+{
+ *(s++) =
+ NEW_HOMEKIT_SERVICE(
+ ACCESSORY_INFORMATION,
+ .id = 1,
+ .characteristics=(homekit_characteristic_t*[]) {
+ NEW_HOMEKIT_CHARACTERISTIC(NAME, "HomePoint"),
+ NEW_HOMEKIT_CHARACTERISTIC(MANUFACTURER, "Homepoint"),
+ NEW_HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "131131"),
+ NEW_HOMEKIT_CHARACTERISTIC(MODEL, "Button"),
+ NEW_HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "0.1"),
+ NEW_HOMEKIT_CHARACTERISTIC(IDENTIFY, switch_identify),
+ NULL
+ },
+ );
+}
+
+void* memdup(void* data, size_t data_size) {
+ void *result = malloc(data_size);
+ memcpy(result, data, data_size);
+ return result;
+ }
+
+ #define NEW_HOMEKIT_CHARACTERISTIC_CALLBACK(...) \
+ memdup(HOMEKIT_CHARACTERISTIC_CALLBACK(__VA_ARGS__), \
+ sizeof(homekit_characteristic_change_callback_t))
+
+void hkAddDevice(const char* deviceName, homekit_characteristic_t *setterChar)
+{
+ bool primary = false;
+ if (currentPos == 0)
+ {
+ primary = true;
+ }
+ *(s++) = NEW_HOMEKIT_SERVICE(
+ SWITCH,
+ .primary = primary,
+ .characteristics=(homekit_characteristic_t*[]) {
+ NEW_HOMEKIT_CHARACTERISTIC(NAME, deviceName),
+ setterChar,
+ NULL
+ });
+ currentPos += 1;
+}
+
+void hkInit(const char* password)
+{
+ *(s++) = NULL;
+ accessories[0] = NEW_HOMEKIT_ACCESSORY(.category=homekit_accessory_category_switch, .services=services);
+ accessories[1] = NULL;
+ config.accessories = accessories;
+ config.password = password;
+ homekit_server_init(&config);
+}
diff --git a/main/homekit/hkapi.h b/main/homekit/hkapi.h
new file mode 100644
index 0000000..1d25ca7
--- /dev/null
+++ b/main/homekit/hkapi.h
@@ -0,0 +1,4 @@
+
+void hkInitService();
+void hkInit(const char* password);
+void hkAddDevice(const char* deviceName, homekit_characteristic_t *setterChar);
diff --git a/main/mqtt/MQTTConnection.cpp b/main/mqtt/MQTTConnection.cpp
index a25d79a..025443e 100644
--- a/main/mqtt/MQTTConnection.cpp
+++ b/main/mqtt/MQTTConnection.cpp
@@ -20,7 +20,7 @@ static const char* TAG = "MQTT";
namespace mqtt
{
- MQTTConnection::MQTTConnection(MQTTConfig config, std::vector mqttscenes) :
+ MQTTConnection::MQTTConnection(MQTTConfig config, std::vector mqttscenes) :
mConfig(config),
mMQTTScenes(mqttscenes)
{
@@ -107,7 +107,11 @@ namespace mqtt
{
auto scene = std::find_if(mMQTTScenes.begin(), mMQTTScenes.end(), [&id](auto& ele)
{
- return mpark::visit([&id](auto&& elem) { return elem->groupId == id; }, ele);
+ return mpark::visit(::util::overloaded([&id](MQTTSwitchGroupPtr&& elem)
+ {
+ return elem->groupId == id;
+ },
+ [](auto&& i) { return false; }), ele);
});
if (scene != mMQTTScenes.end())
{
@@ -133,7 +137,11 @@ namespace mqtt
ESP_LOGI(TAG, "Switching, grp=%d, dev=%d", groupid, deviceid);
auto scene = std::find_if(mMQTTScenes.begin(), mMQTTScenes.end(), [&groupid](auto& ele)
{
- return mpark::visit([&groupid](auto&& elem) { return elem->groupId == groupid; }, ele);
+ return mpark::visit(::util::overloaded([&groupid](MQTTSwitchGroupPtr&& elem)
+ {
+ return elem->groupId == groupid;
+ },
+ [](auto&& i) { return false; }), ele);
});
if (scene != mMQTTScenes.end())
diff --git a/main/mqtt/MQTTConnection.h b/main/mqtt/MQTTConnection.h
index c9b41e6..42dbb3e 100644
--- a/main/mqtt/MQTTConnection.h
+++ b/main/mqtt/MQTTConnection.h
@@ -1,6 +1,6 @@
#pragma once
-#include "MQTTGroup.hpp"
+#include
#include
#include
@@ -35,7 +35,7 @@ namespace mqtt
class MQTTConnection
{
public:
- MQTTConnection(MQTTConfig config, std::vector mqttscenes);
+ MQTTConnection(MQTTConfig config, std::vector mqttscenes);
void connect();
void bindScenes();
void switchScene(const uint16_t id, bool on);
@@ -48,7 +48,7 @@ namespace mqtt
void updateScenes(esp_mqtt_event_handle_t event);
MQTTConfig mConfig;
esp_mqtt_client_handle_t client;
- std::vector mMQTTScenes;
+ std::vector mMQTTScenes;
MQTTConnectionStatus mLastState;
Dispatcher mConnectionStatusNotifier;
};
diff --git a/main/mqtt/MQTTGroup.hpp b/main/mqtt/MQTTGroup.hpp
index cc704ea..657ae14 100644
--- a/main/mqtt/MQTTGroup.hpp
+++ b/main/mqtt/MQTTGroup.hpp
@@ -16,7 +16,6 @@ namespace mqtt { struct MQTTSwitchGroup; struct MQTTGroup; struct MQTTSensorGrou
using MQTTSwitchGroupPtr = std::shared_ptr;
using MQTTSensorGroupPtr = std::shared_ptr;
using MQTTGroupBasePtr = std::shared_ptr;
-using MQTTVariants = mpark::variant;
using MQTTGroupsPtr = std::shared_ptr>;
namespace mqtt
diff --git a/main/ui/UIWidgetBuilder.hpp b/main/ui/UIWidgetBuilder.hpp
index 97e266d..3b5fa3b 100644
--- a/main/ui/UIWidgetBuilder.hpp
+++ b/main/ui/UIWidgetBuilder.hpp
@@ -59,6 +59,39 @@ namespace util
return button;
};
+ auto operator()(HKDevicePtr ptr, ScreenType screen) -> std::shared_ptr
+ {
+ auto button = std::make_shared(&(screen->mTft), Frame(), ptr->groupId);
+ button->setBackgroundColor(Color::InactiveBgColor());
+ button->setLabel(ptr->sceneName);
+
+ const auto icons = GetIconFileNames(ptr->iconName);
+ const auto textColor = ptr->isActive() ? Color::ActiveBgColor() : Color::InactiveTextColor();
+ const auto imagePath = ptr->isActive() ? icons.first : icons.second;
+ button->setImage(imagePath);
+ button->setTextColor(textColor);
+ auto& context = screen->mpAppContext;
+ button->addTargetAction([ptr, context](const uint16_t id) {
+ const bool isActive = ptr->isActive();
+ ptr->setDeviceState(!isActive);
+ });
+
+ auto& screenSaver = screen->mScreenSaver;
+ ptr->mSetNeedsUpdateCB = [ptr, weakBtn = std::weak_ptr(button), &screenSaver, icons](const bool state) {
+ const auto textColor = state ? Color::ActiveBgColor() : Color::InactiveTextColor();
+ const auto imagePath = state ? icons.first : icons.second;
+ auto button = weakBtn.lock();
+ if (!button)
+ {
+ return;
+ }
+ button->setTextColor(textColor);
+ button->setImage(imagePath);
+ screenSaver.activate();
+ };
+ return button;
+ };
+
auto operator()(MQTTSensorGroupPtr ptr, ScreenType screen) -> std::shared_ptr
{
auto button = std::make_shared(&(screen->mTft), Frame(), ptr->groupId);
@@ -137,4 +170,4 @@ namespace util
}
};
} // namespace util
-} // namespace gfx
\ No newline at end of file
+} // namespace gfx
diff --git a/sdkconfig b/sdkconfig
index 01b7f3c..76e2655 100644
--- a/sdkconfig
+++ b/sdkconfig
@@ -516,7 +516,9 @@ CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y
# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set
CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1
CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
-# CONFIG_SPI_FLASH_VERIFY_WRITE is not set
+CONFIG_SPI_FLASH_VERIFY_WRITE=y
+CONFIG_SPI_FLASH_LOG_FAILED_WRITE=y
+# CONFIG_SPI_FLASH_WARN_SETTING_ZERO_TO_ONE is not set
# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
CONFIG_SPIFFS_MAX_PARTITIONS=3
@@ -552,6 +554,10 @@ CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
# CONFIG_WL_SECTOR_SIZE_512 is not set
CONFIG_WL_SECTOR_SIZE_4096=y
CONFIG_WL_SECTOR_SIZE=4096
+CONFIG_HOMEKIT_SPI_FLASH_BASE_ADDR="0x200000"
+CONFIG_HOMEKIT_MAX_CLIENTS=16
+# CONFIG_HOMEKIT_SMALL is not set
+# CONFIG_HOMEKIT_DEBUG is not set
# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set
# Deprecated options for backward compatibility