mirror of
https://github.com/esphome/esphome.git
synced 2024-12-25 23:14:54 +01:00
Remote magiquest protocol (#2963)
Co-authored-by: Aaron Hertz <aaron@rockforest.org> Co-authored-by: Otto Winter <otto@otto-winter.com>
This commit is contained in:
parent
1a8f8adc2a
commit
f137cc10f4
5 changed files with 190 additions and 0 deletions
|
@ -27,6 +27,8 @@ from esphome.const import (
|
|||
CONF_CARRIER_FREQUENCY,
|
||||
CONF_RC_CODE_1,
|
||||
CONF_RC_CODE_2,
|
||||
CONF_MAGNITUDE,
|
||||
CONF_WAND_ID,
|
||||
CONF_LEVEL,
|
||||
)
|
||||
from esphome.core import coroutine
|
||||
|
@ -391,6 +393,54 @@ async def lg_action(var, config, args):
|
|||
cg.add(var.set_nbits(template_))
|
||||
|
||||
|
||||
# MagiQuest
|
||||
(
|
||||
MagiQuestData,
|
||||
MagiQuestBinarySensor,
|
||||
MagiQuestTrigger,
|
||||
MagiQuestAction,
|
||||
MagiQuestDumper,
|
||||
) = declare_protocol("MagiQuest")
|
||||
|
||||
MAGIQUEST_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_WAND_ID): cv.hex_uint32_t,
|
||||
cv.Optional(CONF_MAGNITUDE, default=0xFFFF): cv.hex_uint16_t,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@register_binary_sensor("magiquest", MagiQuestBinarySensor, MAGIQUEST_SCHEMA)
|
||||
def magiquest_binary_sensor(var, config):
|
||||
cg.add(
|
||||
var.set_data(
|
||||
cg.StructInitializer(
|
||||
MagiQuestData,
|
||||
("magnitude", config[CONF_MAGNITUDE]),
|
||||
("wand_id", config[CONF_WAND_ID]),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@register_trigger("magiquest", MagiQuestTrigger, MagiQuestData)
|
||||
def magiquest_trigger(var, config):
|
||||
pass
|
||||
|
||||
|
||||
@register_dumper("magiquest", MagiQuestDumper)
|
||||
def magiquest_dumper(var, config):
|
||||
pass
|
||||
|
||||
|
||||
@register_action("magiquest", MagiQuestAction, MAGIQUEST_SCHEMA)
|
||||
async def magiquest_action(var, config, args):
|
||||
template_ = await cg.templatable(config[CONF_WAND_ID], args, cg.uint32)
|
||||
cg.add(var.set_wand_id(template_))
|
||||
template_ = await cg.templatable(config[CONF_MAGNITUDE], args, cg.uint16)
|
||||
cg.add(var.set_magnitude(template_))
|
||||
|
||||
|
||||
# NEC
|
||||
NECData, NECBinarySensor, NECTrigger, NECAction, NECDumper = declare_protocol("NEC")
|
||||
NEC_SCHEMA = cv.Schema(
|
||||
|
|
83
esphome/components/remote_base/magiquest_protocol.cpp
Normal file
83
esphome/components/remote_base/magiquest_protocol.cpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
#include "magiquest_protocol.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
/* Based on protocol analysis from
|
||||
* https://arduino-irremote.github.io/Arduino-IRremote/ir__MagiQuest_8cpp_source.html
|
||||
*/
|
||||
|
||||
namespace esphome {
|
||||
namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.magiquest";
|
||||
|
||||
static const uint32_t MAGIQUEST_UNIT = 288; // us
|
||||
static const uint32_t MAGIQUEST_ONE_MARK = 2 * MAGIQUEST_UNIT;
|
||||
static const uint32_t MAGIQUEST_ONE_SPACE = 2 * MAGIQUEST_UNIT;
|
||||
static const uint32_t MAGIQUEST_ZERO_MARK = MAGIQUEST_UNIT;
|
||||
static const uint32_t MAGIQUEST_ZERO_SPACE = 3 * MAGIQUEST_UNIT;
|
||||
|
||||
void MagiQuestProtocol::encode(RemoteTransmitData *dst, const MagiQuestData &data) {
|
||||
dst->reserve(101); // 2 start bits, 48 data bits, 1 stop bit
|
||||
dst->set_carrier_frequency(38000);
|
||||
|
||||
// 2 start bits
|
||||
dst->item(MAGIQUEST_ZERO_MARK, MAGIQUEST_ZERO_SPACE);
|
||||
dst->item(MAGIQUEST_ZERO_MARK, MAGIQUEST_ZERO_SPACE);
|
||||
for (uint32_t mask = 1 << 31; mask; mask >>= 1) {
|
||||
if (data.wand_id & mask) {
|
||||
dst->item(MAGIQUEST_ONE_MARK, MAGIQUEST_ONE_SPACE);
|
||||
} else {
|
||||
dst->item(MAGIQUEST_ZERO_MARK, MAGIQUEST_ZERO_SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t mask = 1 << 15; mask; mask >>= 1) {
|
||||
if (data.magnitude & mask) {
|
||||
dst->item(MAGIQUEST_ONE_MARK, MAGIQUEST_ONE_SPACE);
|
||||
} else {
|
||||
dst->item(MAGIQUEST_ZERO_MARK, MAGIQUEST_ZERO_SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
dst->mark(MAGIQUEST_UNIT);
|
||||
}
|
||||
optional<MagiQuestData> MagiQuestProtocol::decode(RemoteReceiveData src) {
|
||||
MagiQuestData data{
|
||||
.magnitude = 0,
|
||||
.wand_id = 0,
|
||||
};
|
||||
// Two start bits
|
||||
if (!src.expect_item(MAGIQUEST_ZERO_MARK, MAGIQUEST_ZERO_SPACE) ||
|
||||
!src.expect_item(MAGIQUEST_ZERO_MARK, MAGIQUEST_ZERO_SPACE)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
for (uint32_t mask = 1 << 31; mask; mask >>= 1) {
|
||||
if (src.expect_item(MAGIQUEST_ONE_MARK, MAGIQUEST_ONE_SPACE)) {
|
||||
data.wand_id |= mask;
|
||||
} else if (src.expect_item(MAGIQUEST_ZERO_MARK, MAGIQUEST_ZERO_SPACE)) {
|
||||
data.wand_id &= ~mask;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t mask = 1 << 15; mask; mask >>= 1) {
|
||||
if (src.expect_item(MAGIQUEST_ONE_MARK, MAGIQUEST_ONE_SPACE)) {
|
||||
data.magnitude |= mask;
|
||||
} else if (src.expect_item(MAGIQUEST_ZERO_MARK, MAGIQUEST_ZERO_SPACE)) {
|
||||
data.magnitude &= ~mask;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
src.expect_mark(MAGIQUEST_UNIT);
|
||||
return data;
|
||||
}
|
||||
void MagiQuestProtocol::dump(const MagiQuestData &data) {
|
||||
ESP_LOGD(TAG, "Received MagiQuest: wand_id=0x%08X, magnitude=0x%04X", data.wand_id, data.magnitude);
|
||||
}
|
||||
|
||||
} // namespace remote_base
|
||||
} // namespace esphome
|
50
esphome/components/remote_base/magiquest_protocol.h
Normal file
50
esphome/components/remote_base/magiquest_protocol.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include "remote_base.h"
|
||||
|
||||
/* Based on protocol analysis from
|
||||
* https://arduino-irremote.github.io/Arduino-IRremote/ir__MagiQuest_8cpp_source.html
|
||||
*/
|
||||
|
||||
namespace esphome {
|
||||
namespace remote_base {
|
||||
|
||||
struct MagiQuestData {
|
||||
uint16_t magnitude;
|
||||
uint32_t wand_id;
|
||||
|
||||
bool operator==(const MagiQuestData &rhs) const {
|
||||
// Treat 0xffff as a special, wildcard magnitude
|
||||
// In testing, the wand never produces this value, and this allows us to match
|
||||
// on just the wand_id if wanted.
|
||||
if (rhs.wand_id != this->wand_id) {
|
||||
return false;
|
||||
}
|
||||
return (this->wand_id == 0xffff || rhs.wand_id == 0xffff || this->wand_id == rhs.wand_id);
|
||||
}
|
||||
};
|
||||
|
||||
class MagiQuestProtocol : public RemoteProtocol<MagiQuestData> {
|
||||
public:
|
||||
void encode(RemoteTransmitData *dst, const MagiQuestData &data) override;
|
||||
optional<MagiQuestData> decode(RemoteReceiveData src) override;
|
||||
void dump(const MagiQuestData &data) override;
|
||||
};
|
||||
|
||||
DECLARE_REMOTE_PROTOCOL(MagiQuest)
|
||||
|
||||
template<typename... Ts> class MagiQuestAction : public RemoteTransmitterActionBase<Ts...> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(uint16_t, magnitude)
|
||||
TEMPLATABLE_VALUE(uint32_t, wand_id)
|
||||
|
||||
void encode(RemoteTransmitData *dst, Ts... x) override {
|
||||
MagiQuestData data{};
|
||||
data.magnitude = this->magnitude_.value(x...);
|
||||
data.wand_id = this->wand_id_.value(x...);
|
||||
MagiQuestProtocol().encode(dst, data);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace remote_base
|
||||
} // namespace esphome
|
|
@ -344,6 +344,7 @@ CONF_LOOP_TIME = "loop_time"
|
|||
CONF_LOW = "low"
|
||||
CONF_LOW_VOLTAGE_REFERENCE = "low_voltage_reference"
|
||||
CONF_MAC_ADDRESS = "mac_address"
|
||||
CONF_MAGNITUDE = "magnitude"
|
||||
CONF_MAINS_FILTER = "mains_filter"
|
||||
CONF_MAKE_ID = "make_id"
|
||||
CONF_MANUAL_IP = "manual_ip"
|
||||
|
@ -735,6 +736,7 @@ CONF_VOLTAGE_DIVIDER = "voltage_divider"
|
|||
CONF_WAIT_TIME = "wait_time"
|
||||
CONF_WAIT_UNTIL = "wait_until"
|
||||
CONF_WAKEUP_PIN = "wakeup_pin"
|
||||
CONF_WAND_ID = "wand_id"
|
||||
CONF_WARM_WHITE = "warm_white"
|
||||
CONF_WARM_WHITE_COLOR_TEMPERATURE = "warm_white_color_temperature"
|
||||
CONF_WATCHDOG_THRESHOLD = "watchdog_threshold"
|
||||
|
|
|
@ -1861,6 +1861,11 @@ switch:
|
|||
turn_on_action:
|
||||
remote_transmitter.transmit_jvc:
|
||||
data: 0x10EF
|
||||
- platform: template
|
||||
name: MagiQuest
|
||||
turn_on_action:
|
||||
remote_transmitter.transmit_magiquest:
|
||||
wand_id: 0x01234567
|
||||
- platform: template
|
||||
name: NEC
|
||||
id: living_room_lights_off
|
||||
|
|
Loading…
Reference in a new issue