I've narrowed the problem to be when trying to send the IR command. But can't wrap my head around where or what might be causing the issue.
A brief explanation:
There's an `IRTransceiver` class that handles the rmt driver initialisation and interfaces with it in order to send the IR command. This is passed to an `AirConditioner` object that is intended to hold the state of the AC unit as selected on the controller APP. At the moment it is only a placeholder as `state` is not being updated anywhere in the code, and it always sends the same state value. `State` is not being modified anywhere in the code. Just sent whenever the `power` property is changed.
With this in mind, this seems to point to the root of the problem. When initialised, `state` is this as shown on log with `ESP_LOG` calls:
Code: Select all
I (934) AirConditioner: State is init here, contents:
I (944) AirConditioner: ==========================
I (944) AirConditioner: ==========================
I (954) AirConditioner: ==========================
I (954) AirConditioner: ========= STATE ==========
I (964) AirConditioner: 131
I (964) AirConditioner: 6
I (974) AirConditioner: 4
I (974) AirConditioner: 114
I (974) AirConditioner: 0
I (984) AirConditioner: 0
I (984) AirConditioner: 148
I (984) AirConditioner: 56
I (994) AirConditioner: 0
I (994) AirConditioner: 0
I (994) AirConditioner: 0
I (1004) AirConditioner: 128
I (1004) AirConditioner: 25
I (1004) AirConditioner: 67
I (1014) AirConditioner: 0
I (1014) AirConditioner: 1
I (1014) AirConditioner: 0
I (1024) AirConditioner: 0
I (1024) AirConditioner: 0
I (1024) AirConditioner: 0
I (1034) AirConditioner: 1
I (1034) AirConditioner: ======= END STATE ========
I (1044) AirConditioner: ==========================
I (1044) AirConditioner: ==========================
I (1054) AirConditioner: ==========================
Code: Select all
I (13244) AirConditioner: SetPower called
I (13244) AirConditioner: Setting new power value
I (13254) AirConditioner: Sending new state...
I (13254) AirConditioner: passing state for sending.
I (13264) AirConditioner: ==========================
I (13264) AirConditioner: ==========================
I (13274) AirConditioner: ==========================
I (13274) AirConditioner: ========= STATE ==========
I (13274) AirConditioner: 0
I (13294) AirConditioner: 0
I (13294) AirConditioner: 0
I (13294) AirConditioner: 0
I (13304) AirConditioner: 0
I (13304) AirConditioner: 0
I (13304) AirConditioner: 0
I (13304) AirConditioner: 0
I (13314) AirConditioner: 0
I (13314) AirConditioner: 60
I (13314) AirConditioner: 55
I (13314) AirConditioner: 64
I (13324) AirConditioner: 63
I (13334) AirConditioner: 48
I (13334) AirConditioner: 188
I (13334) AirConditioner: 251
I (13344) AirConditioner: 63
I (13344) AirConditioner: 16
I (13344) AirConditioner: 188
I (13354) AirConditioner: 251
I (13354) AirConditioner: 63
I (13354) AirConditioner: ======= END STATE ========
I (13374) AirConditioner: ==========================
I (13374) AirConditioner: ==========================
I (13374) AirConditioner: ==========================
Matter requires for a series of callbacks to be implemented and the `AirConditioner` object is passed as a reference as priv_data so it can be recalled afterwards on the callback:
Code: Select all
esp_err_t matterDriverInit(AirConditioner ac) {
node::config_t nodeConfig;
node_t *node = node::create(&nodeConfig, handleAttributeUpdate, handleIdentification);
on_off_plugin_unit::config_t acConfig;
acConfig.on_off.on_off = false;
endpoint_t *endpoint = on_off_plugin_unit::create(node, &acConfig, ENDPOINT_FLAG_NONE, &ac);
//other stuff
}
[code]
then on the callback used for attribute update handling it is casted back to `AirConditioner`:
[code]
esp_err_t handleAttributeUpdate(attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) {
esp_err_t err = ESP_OK;
if(endpoint_id == acEndpointId) {
AirConditioner* ac = (AirConditioner*)priv_data;
if (cluster_id == OnOff::Id) {
if(attribute_id == OnOff::Attributes::OnOff::Id) {
ac->setPower(val->val.b); // this calls for sendstate afterwards.
}
}
}
}
//else for error if needed...
return err;
Then `sendState()`simply passes the `state` property to the `IRTransceiver` so it can be sent through the IR transmitter.
Code: Select all
void AirConditioner::sendState() {
#ifdef DEBUG
ESP_LOGI(TAG_AC, "passing state for sending.");
ESP_LOGI(TAG_AC, "==========================");
ESP_LOGI(TAG_AC, "==========================");
ESP_LOGI(TAG_AC, "==========================");
ESP_LOGI(TAG_AC, "========= STATE ==========");
for (int i=0; i<21; i++) {
ESP_LOGI(TAG_AC, "%d ", this->state[i] );
}
ESP_LOGI(TAG_AC, "======= END STATE ========");
ESP_LOGI(TAG_AC, "==========================");
ESP_LOGI(TAG_AC, "==========================");
ESP_LOGI(TAG_AC, "==========================");
#endif
//this->transceiver.sendIRCommand(this->state);
this->transceiver.sendDefaultState();//workaround
}
Code: Select all
size_t IRTransceiver::sendIRCommand(uint8_t state[21]){
#ifdef DEBUG
ESP_LOGI(TAG, "State received:");
ESP_LOGI(TAG, "==========================");
ESP_LOGI(TAG, "==========================");
ESP_LOGI(TAG, "==========================");
ESP_LOGI(TAG, "========= STATE ==========");
for (int i=0; i<21; i++) {
ESP_LOGI(TAG, "%d ", state[i] );
}
ESP_LOGI(TAG, "======= END STATE ========");
ESP_LOGI(TAG, "==========================");
ESP_LOGI(TAG, "==========================");
ESP_LOGI(TAG, "==========================");
#endif
ESP_LOGI(TAG, "Sending IR Command");
return rmt_transmit(this->txChannel, this->encoder, &state, sizeof(&state), &this->txConfig);
}
size_t IRTransceiver::sendDefaultState(){
ESP_LOGI(TAG, "Sending IR Command for default state");
uint8_t defaultState[21] = {0x83, 0x06, 0x04, 0x72, 0x00, 0x00, 0x94, 0x38, 0x00, 0x00, 0x00, 0x80, 0x19, 0x43, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01};
return rmt_transmit(this->txChannel, this->encoder, &defaultState, sizeof(&defaultState), &this->txConfig);
ESP_LOGI(TAG, "Sent IR Command");
}
However, when using it from a debug main directly without involving callbacks, they work as expected, the command is sent and the system doesn't crash which point to proper implementation on `IRTransceiver` and `AirConditioner`
Code: Select all
extern "C" void app_main() {
std::string protocol = "KELON168";
//Initialize IR TX
IRTransceiver transceiver(IR_TX_PIN,protocol);
esp_err_t res = transceiver.enableTx();
if (res == ESP_OK) {
ESP_LOGI("DEBUG_IR", "sucessfully enabled IR transmission");
}
else {
ESP_LOGI("DEBUG_IR", "error enabling IR transmission");
}
AirConditioner ac(25,1,1,false,transceiver);
if (res == ESP_OK) {
ESP_LOGI("DEBUG_IR", "sucessfully enabled IR transmission");
}
else {
ESP_LOGI("DEBUG_IR", "error enabling IR transmission");
}
ESP_LOGI("DEBUG_IR", "Updating power to true");
ac.setPower(true);
ESP_LOGI("DEBUG_IR", "Updating power to false");
ac.setPower(false);
ESP_LOGI("DEBUG_IR", "did not crash :o");
}
Any ideas?