maximkulkin / esp-homekit-demo

Demo of Apple HomeKit accessory server library
MIT License
809 stars 233 forks source link

Creating heater help. #283

Closed kenthinson closed 4 years ago

kenthinson commented 4 years ago

Hello I am attempting to create a heater using the thermostat code as an example. Despite the fact that I've striped out all the cooling declaration that I can see. I still cooling as an option in the HomeKit app. Can you point out where I'm going wrong? After I get the heater working I would be happy to contribute it back as an example file.

/*
 * Heater example
 *
 * Wiring is as follows (requires ESP-12 as it needs 4 GPIOs):
 *
 * DHT11 (temperature sensor)
 *
 *               -------------
 *              |GND       VCC|    (These go to control pins of relay)
 *              |15         13| --> Heater
 *              |2          12| --> Cooler
 *              |0          14| --> Fan
 *              |5          16|
 * DHT Data <-- |4       CH_PD|
 *              |RXD       ADC|
 *              |TXD      REST|
 *               -------------
 *              |   |-| |-| | |
 *              | __| |_| |_| |
 *               -------------
 *
 */
#include <stdio.h>
#include <espressif/esp_wifi.h>
#include <espressif/esp_sta.h>
#include <espressif/esp_system.h>
#include <esp/uart.h>
#include <esp8266.h>
#include <etstimer.h>
#include <esplibs/libmain.h>
#include <FreeRTOS.h>
#include <task.h>

#include <homekit/homekit.h>
#include <homekit/characteristics.h>
#include "wifi.h"

#include <dht/dht.h>

#define LED_PIN 2
#define TEMPERATURE_SENSOR_PIN 4
#define FAN_PIN 14
#define COOLER_PIN 12
#define HEATER_PIN 13
#define TEMPERATURE_POLL_PERIOD 10000
#define HEATER_FAN_DELAY 30000
#define COOLER_FAN_DELAY 0

static void wifi_init() {
    struct sdk_station_config wifi_config = {
        .ssid = WIFI_SSID,
        .password = WIFI_PASSWORD,
    };

    sdk_wifi_set_opmode(STATION_MODE);
    sdk_wifi_station_set_config(&wifi_config);
    sdk_wifi_station_connect();
}

void heater_identify(homekit_value_t _value) {
    printf("Heater identify\n");
}

ETSTimer fan_timer;

void heaterOn() {
    gpio_write(HEATER_PIN, false);
}

void heaterOff() {
    gpio_write(HEATER_PIN, true);
}

void coolerOn() {
    gpio_write(COOLER_PIN, false);
}

void coolerOff() {
    gpio_write(COOLER_PIN, true);
}

void fan_alarm(void *arg) {
    gpio_write(FAN_PIN, false);
}

void fanOn(uint16_t delay) {
    if (delay > 0) {
        sdk_os_timer_arm(&fan_timer, delay, false);
    } else {
        gpio_write(FAN_PIN, false);
    }
}

void fanOff() {
    sdk_os_timer_disarm(&fan_timer);
    gpio_write(FAN_PIN, true);
}

void update_state();

void on_update(homekit_characteristic_t *ch, homekit_value_t value, void *context) {
    update_state();
}

homekit_characteristic_t current_temperature = HOMEKIT_CHARACTERISTIC_(
    CURRENT_TEMPERATURE, 0
);
homekit_characteristic_t units = HOMEKIT_CHARACTERISTIC_(TEMPERATURE_DISPLAY_UNITS, 0);
homekit_characteristic_t current_state = HOMEKIT_CHARACTERISTIC_(CURRENT_HEATER_COOLER_STATE, 0);
homekit_characteristic_t target_state = HOMEKIT_CHARACTERISTIC_(
    TARGET_HEATER_COOLER_STATE, 0, .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(on_update)
);
homekit_characteristic_t heating_threshold = HOMEKIT_CHARACTERISTIC_(
    HEATING_THRESHOLD_TEMPERATURE, 15, .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(on_update)
);

void update_state() {
    // uint8_t state = target_state.value.int_value;
    // if ((state == 1 && current_temperature.value.float_value < target_temperature.value.float_value) ||
    //         (state == 3 && current_temperature.value.float_value < heating_threshold.value.float_value)) {
    //     if (current_state.value.int_value != 1) {
    //         current_state.value = HOMEKIT_UINT8(1);
    //         homekit_characteristic_notify(&current_state, current_state.value);

    //         heaterOn();
    //         coolerOff();
    //         fanOff();
    //         fanOn(HEATER_FAN_DELAY);
    //     }
    // // } else if ((state == 2 && current_temperature.value.float_value > target_temperature.value.float_value) ||
    // //         (state == 3 && current_temperature.value.float_value > cooling_threshold.value.float_value)) {
    // //     if (current_state.value.int_value != 2) {
    // //         current_state.value = HOMEKIT_UINT8(2);
    // //         homekit_characteristic_notify(&current_state, current_state.value);

    // //         coolerOn();
    // //         heaterOff();
    // //         fanOff();
    // //         fanOn(COOLER_FAN_DELAY);
    // //     }
    // } else {
    //     if (current_state.value.int_value != 0) {
    //         current_state.value = HOMEKIT_UINT8(0);
    //         homekit_characteristic_notify(&current_state, current_state.value);

    //         coolerOff();
    //         heaterOff();
    //         fanOff();
    //     }
    // }
}

void temperature_sensor_task(void *_args) {
    sdk_os_timer_setfn(&fan_timer, fan_alarm, NULL);

    gpio_set_pullup(TEMPERATURE_SENSOR_PIN, false, false);

    gpio_enable(FAN_PIN, GPIO_OUTPUT);
    gpio_enable(HEATER_PIN, GPIO_OUTPUT);
    gpio_enable(COOLER_PIN, GPIO_OUTPUT);

    fanOff();
    heaterOff();
    coolerOff();

    float humidity_value, temperature_value;
    while (1) {
        bool success = dht_read_float_data(
            DHT_TYPE_DHT11, TEMPERATURE_SENSOR_PIN,
            &humidity_value, &temperature_value
        );
        if (success) {
            printf("Got readings: temperature %g, humidity %g\n", temperature_value, humidity_value);
            current_temperature.value = HOMEKIT_FLOAT(temperature_value);

            homekit_characteristic_notify(&current_temperature, current_temperature.value);

            update_state();
        } else {
            printf("Couldnt read data from sensor\n");
        }

        vTaskDelay(TEMPERATURE_POLL_PERIOD / portTICK_PERIOD_MS);
    }
}

void heater_init() {
    xTaskCreate(temperature_sensor_task, "Heater", 256, NULL, 2, NULL);
}

homekit_accessory_t *accessories[] = {
    HOMEKIT_ACCESSORY(.id=1, .category=homekit_accessory_category_heater, .services=(homekit_service_t*[]) {
        HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]) {
            HOMEKIT_CHARACTERISTIC(NAME, "Heater"),
            HOMEKIT_CHARACTERISTIC(MANUFACTURER, "HaPK"),
            HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "001"),
            HOMEKIT_CHARACTERISTIC(MODEL, "MyHeater"),
            HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "0.1"),
            HOMEKIT_CHARACTERISTIC(IDENTIFY, heater_identify),
            NULL
        }),
        HOMEKIT_SERVICE(HEATER_COOLER, .primary=true, .characteristics=(homekit_characteristic_t*[]) {
            HOMEKIT_CHARACTERISTIC(NAME, "Heater"),
            &current_temperature,
            &current_state,
            &target_state,
            &heating_threshold,
            &units,
            NULL
        }),
        NULL
    }),
    NULL
};

homekit_server_config_t config = {
    .accessories = accessories,
    .password = "111-11-111"
};

void user_init(void) {
    uart_set_baud(0, 115200);

    wifi_init();
    heater_init();
    homekit_server_init(&config);
}

IMG_0375

kenthinson commented 4 years ago

I found this information looks the same but it's for Homebridge. Not sure how to translate it over to this library. https://github.com/nfarina/homebridge/issues/2239

HomeKidd commented 4 years ago

Change the Current State and Target State based on that:

homekit_characteristic_t current_state = HOMEKIT_CHARACTERISTIC_(CURRENT_HEATING_COOLING_STATE, 0, .valid_values={.count=2, .values=(uint8_t[]) {0, 1}}; // Only OFF/HEAT state
homekit_characteristic_t target_state = HOMEKIT_CHARACTERISTIC_(TARGET_HEATING_COOLING_STATE, 0, .valid_values={.count=2, .values=(uint8_t[]) {0, 1}}, .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(on_update)); // Only OFF/HEAT state

It basically sets the values to be only OFF and HEAT (0 and 1) so the Cooling option will be invisible in the Home app 😄

kenthinson commented 4 years ago

@HomeKidd nice thanks!