Merge branch 'dev' into smartconfig

This commit is contained in:
vinhpn96 2024-02-18 16:46:59 +07:00 committed by GitHub
commit 085eb03ced
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
344 changed files with 9292 additions and 61 deletions

View File

@ -199,6 +199,7 @@ esphome/components/mcp9808/* @k7hpn
esphome/components/md5/* @esphome/core esphome/components/md5/* @esphome/core
esphome/components/mdns/* @esphome/core esphome/components/mdns/* @esphome/core
esphome/components/media_player/* @jesserockz esphome/components/media_player/* @jesserockz
esphome/components/micro_wake_word/* @jesserockz @kahrendt
esphome/components/micronova/* @jorre05 esphome/components/micronova/* @jorre05
esphome/components/microphone/* @jesserockz esphome/components/microphone/* @jesserockz
esphome/components/mics_4514/* @jesserockz esphome/components/mics_4514/* @jesserockz

View File

@ -35,7 +35,7 @@ RUN \
iputils-ping=3:20221126-1 \ iputils-ping=3:20221126-1 \
git=1:2.39.2-1.1 \ git=1:2.39.2-1.1 \
curl=7.88.1-10+deb12u5 \ curl=7.88.1-10+deb12u5 \
openssh-client=1:9.2p1-2+deb12u1 \ openssh-client=1:9.2p1-2+deb12u2 \
python3-cffi=1.15.1-5 \ python3-cffi=1.15.1-5 \
libcairo2=1.16.0-7 \ libcairo2=1.16.0-7 \
libmagic1=1:5.44-3 \ libmagic1=1:5.44-3 \

View File

@ -1,6 +1,8 @@
#include "cse7766.h" #include "cse7766.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <cinttypes> #include <cinttypes>
#include <iomanip>
#include <sstream>
namespace esphome { namespace esphome {
namespace cse7766 { namespace cse7766 {
@ -68,20 +70,26 @@ bool CSE7766Component::check_byte_() {
return true; return true;
} }
void CSE7766Component::parse_data_() { void CSE7766Component::parse_data_() {
ESP_LOGVV(TAG, "CSE7766 Data: "); #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
for (uint8_t i = 0; i < 23; i++) { {
ESP_LOGVV(TAG, " %u: 0b" BYTE_TO_BINARY_PATTERN " (0x%02X)", i + 1, BYTE_TO_BINARY(this->raw_data_[i]), std::stringstream ss;
this->raw_data_[i]); ss << "Raw data:" << std::hex << std::uppercase << std::setfill('0');
for (uint8_t i = 0; i < 23; i++) {
ss << ' ' << std::setw(2) << static_cast<unsigned>(this->raw_data_[i]);
}
ESP_LOGVV(TAG, "%s", ss.str().c_str());
} }
#endif
// Parse header
uint8_t header1 = this->raw_data_[0]; uint8_t header1 = this->raw_data_[0];
if (header1 == 0xAA) { if (header1 == 0xAA) {
ESP_LOGE(TAG, "CSE7766 not calibrated!"); ESP_LOGE(TAG, "CSE7766 not calibrated!");
return; return;
} }
bool power_cycle_exceeds_range = false; bool power_cycle_exceeds_range = false;
if ((header1 & 0xF0) == 0xF0) { if ((header1 & 0xF0) == 0xF0) {
if (header1 & 0xD) { if (header1 & 0xD) {
ESP_LOGE(TAG, "CSE7766 reports abnormal external circuit or chip damage: (0x%02X)", header1); ESP_LOGE(TAG, "CSE7766 reports abnormal external circuit or chip damage: (0x%02X)", header1);
@ -94,74 +102,106 @@ void CSE7766Component::parse_data_() {
if (header1 & (1 << 0)) { if (header1 & (1 << 0)) {
ESP_LOGE(TAG, " Coefficient storage area is abnormal."); ESP_LOGE(TAG, " Coefficient storage area is abnormal.");
} }
// Datasheet: voltage or current cycle exceeding range means invalid values
return; return;
} }
power_cycle_exceeds_range = header1 & (1 << 1); power_cycle_exceeds_range = header1 & (1 << 1);
} }
uint32_t voltage_calib = this->get_24_bit_uint_(2); // Parse data frame
uint32_t voltage_coeff = this->get_24_bit_uint_(2);
uint32_t voltage_cycle = this->get_24_bit_uint_(5); uint32_t voltage_cycle = this->get_24_bit_uint_(5);
uint32_t current_calib = this->get_24_bit_uint_(8); uint32_t current_coeff = this->get_24_bit_uint_(8);
uint32_t current_cycle = this->get_24_bit_uint_(11); uint32_t current_cycle = this->get_24_bit_uint_(11);
uint32_t power_calib = this->get_24_bit_uint_(14); uint32_t power_coeff = this->get_24_bit_uint_(14);
uint32_t power_cycle = this->get_24_bit_uint_(17); uint32_t power_cycle = this->get_24_bit_uint_(17);
uint8_t adj = this->raw_data_[20]; uint8_t adj = this->raw_data_[20];
uint32_t cf_pulses = (this->raw_data_[21] << 8) + this->raw_data_[22]; uint32_t cf_pulses = (this->raw_data_[21] << 8) + this->raw_data_[22];
bool have_power = adj & 0x10;
bool have_current = adj & 0x20;
bool have_voltage = adj & 0x40; bool have_voltage = adj & 0x40;
float voltage = 0.0f;
if (have_voltage) { if (have_voltage) {
// voltage cycle of serial port outputted is a complete cycle; voltage = voltage_coeff / float(voltage_cycle);
float voltage = voltage_calib / float(voltage_cycle); if (this->voltage_sensor_ != nullptr) {
if (this->voltage_sensor_ != nullptr)
this->voltage_sensor_->publish_state(voltage); this->voltage_sensor_->publish_state(voltage);
}
} }
bool have_power = adj & 0x10;
float power = 0.0f; float power = 0.0f;
float energy = 0.0f;
if (have_power) { if (power_cycle_exceeds_range) {
// power cycle of serial port outputted is a complete cycle; // Datasheet: power cycle exceeding range means active power is 0
// According to the user manual, power cycle exceeding range means the measured power is 0 if (this->power_sensor_ != nullptr) {
if (!power_cycle_exceeds_range) { this->power_sensor_->publish_state(0.0f);
power = power_calib / float(power_cycle);
} }
if (this->power_sensor_ != nullptr) } else if (have_power) {
power = power_coeff / float(power_cycle);
if (this->power_sensor_ != nullptr) {
this->power_sensor_->publish_state(power); this->power_sensor_->publish_state(power);
}
// Add CF pulses to the total energy only if we have Power coefficient to multiply by
uint32_t difference;
if (this->cf_pulses_last_ == 0) { if (this->cf_pulses_last_ == 0) {
this->cf_pulses_last_ = cf_pulses; this->cf_pulses_last_ = cf_pulses;
} }
uint32_t cf_diff;
if (cf_pulses < this->cf_pulses_last_) { if (cf_pulses < this->cf_pulses_last_) {
difference = cf_pulses + (0x10000 - this->cf_pulses_last_); cf_diff = cf_pulses + (0x10000 - this->cf_pulses_last_);
} else { } else {
difference = cf_pulses - this->cf_pulses_last_; cf_diff = cf_pulses - this->cf_pulses_last_;
} }
this->cf_pulses_last_ = cf_pulses; this->cf_pulses_last_ = cf_pulses;
this->energy_total_ += difference * float(power_calib) / 1000000.0f / 3600.0f;
energy = cf_diff * float(power_coeff) / 1000000.0f / 3600.0f;
this->energy_total_ += energy;
if (this->energy_sensor_ != nullptr) if (this->energy_sensor_ != nullptr)
this->energy_sensor_->publish_state(this->energy_total_); this->energy_sensor_->publish_state(this->energy_total_);
} else if ((this->energy_sensor_ != nullptr) && !this->energy_sensor_->has_state()) { } else if ((this->energy_sensor_ != nullptr) && !this->energy_sensor_->has_state()) {
this->energy_sensor_->publish_state(0); this->energy_sensor_->publish_state(0);
} }
if (adj & 0x20) { float current = 0.0f;
// indicates current cycle of serial port outputted is a complete cycle; float calculated_current = 0.0f;
float current = 0.0f; if (have_current) {
if (have_voltage && !have_power) { // Assumption: if we don't have power measurement, then current is likely below 50mA
// Testing has shown that when we have voltage and current but not power, that means the power is 0. if (have_power && voltage > 1.0f) {
// We report a power of 0, which in turn means we should report a current of 0. calculated_current = power / voltage;
if (this->power_sensor_ != nullptr)
this->power_sensor_->publish_state(0);
} else if (power != 0.0f) {
current = current_calib / float(current_cycle);
} }
if (this->current_sensor_ != nullptr) // Datasheet: minimum measured current is 50mA
if (calculated_current > 0.05f) {
current = current_coeff / float(current_cycle);
}
if (this->current_sensor_ != nullptr) {
this->current_sensor_->publish_state(current); this->current_sensor_->publish_state(current);
}
} }
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
{
std::stringstream ss;
ss << "Parsed:";
if (have_voltage) {
ss << " V=" << voltage << "V";
}
if (have_current) {
ss << " I=" << current * 1000.0f << "mA (~" << calculated_current * 1000.0f << "mA)";
}
if (have_power) {
ss << " P=" << power << "W";
}
if (energy != 0.0f) {
ss << " E=" << energy << "kWh (" << cf_pulses << ")";
}
ESP_LOGVV(TAG, "%s", ss.str().c_str());
}
#endif
} }
uint32_t CSE7766Component::get_24_bit_uint_(uint8_t start_index) { uint32_t CSE7766Component::get_24_bit_uint_(uint8_t start_index) {

View File

@ -161,10 +161,12 @@ light::ESPColorView ESP32RMTLEDStripLightOutput::get_view_internal(int32_t index
break; break;
} }
uint8_t multiplier = this->is_rgbw_ ? 4 : 3; uint8_t multiplier = this->is_rgbw_ ? 4 : 3;
return {this->buf_ + (index * multiplier) + r, uint8_t white = this->is_wrgb_ ? 0 : 3;
this->buf_ + (index * multiplier) + g,
this->buf_ + (index * multiplier) + b, return {this->buf_ + (index * multiplier) + r + this->is_wrgb_,
this->is_rgbw_ ? this->buf_ + (index * multiplier) + 3 : nullptr, this->buf_ + (index * multiplier) + g + this->is_wrgb_,
this->buf_ + (index * multiplier) + b + this->is_wrgb_,
this->is_rgbw_ || this->is_wrgb_ ? this->buf_ + (index * multiplier) + white : nullptr,
&this->effect_data_[index], &this->effect_data_[index],
&this->correction_}; &this->correction_};
} }

View File

@ -33,7 +33,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
int32_t size() const override { return this->num_leds_; } int32_t size() const override { return this->num_leds_; }
light::LightTraits get_traits() override { light::LightTraits get_traits() override {
auto traits = light::LightTraits(); auto traits = light::LightTraits();
if (this->is_rgbw_) { if (this->is_rgbw_ || this->is_wrgb_) {
traits.set_supported_color_modes({light::ColorMode::RGB_WHITE, light::ColorMode::WHITE}); traits.set_supported_color_modes({light::ColorMode::RGB_WHITE, light::ColorMode::WHITE});
} else { } else {
traits.set_supported_color_modes({light::ColorMode::RGB}); traits.set_supported_color_modes({light::ColorMode::RGB});
@ -44,6 +44,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
void set_pin(uint8_t pin) { this->pin_ = pin; } void set_pin(uint8_t pin) { this->pin_ = pin; }
void set_num_leds(uint16_t num_leds) { this->num_leds_ = num_leds; } void set_num_leds(uint16_t num_leds) { this->num_leds_ = num_leds; }
void set_is_rgbw(bool is_rgbw) { this->is_rgbw_ = is_rgbw; } void set_is_rgbw(bool is_rgbw) { this->is_rgbw_ = is_rgbw; }
void set_is_wrgb(bool is_wrgb) { this->is_wrgb_ = is_wrgb; }
/// Set a maximum refresh rate in µs as some lights do not like being updated too often. /// Set a maximum refresh rate in µs as some lights do not like being updated too often.
void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; } void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
@ -72,6 +73,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
uint8_t pin_; uint8_t pin_;
uint16_t num_leds_; uint16_t num_leds_;
bool is_rgbw_; bool is_rgbw_;
bool is_wrgb_;
rmt_item32_t bit0_, bit1_; rmt_item32_t bit0_, bit1_;
RGBOrder rgb_order_; RGBOrder rgb_order_;

View File

@ -52,6 +52,7 @@ CHIPSETS = {
CONF_IS_RGBW = "is_rgbw" CONF_IS_RGBW = "is_rgbw"
CONF_IS_WRGB = "is_wrgb"
CONF_BIT0_HIGH = "bit0_high" CONF_BIT0_HIGH = "bit0_high"
CONF_BIT0_LOW = "bit0_low" CONF_BIT0_LOW = "bit0_low"
CONF_BIT1_HIGH = "bit1_high" CONF_BIT1_HIGH = "bit1_high"
@ -90,6 +91,7 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds,
cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True), cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True),
cv.Optional(CONF_IS_RGBW, default=False): cv.boolean, cv.Optional(CONF_IS_RGBW, default=False): cv.boolean,
cv.Optional(CONF_IS_WRGB, default=False): cv.boolean,
cv.Inclusive( cv.Inclusive(
CONF_BIT0_HIGH, CONF_BIT0_HIGH,
"custom", "custom",
@ -145,6 +147,7 @@ async def to_code(config):
cg.add(var.set_rgb_order(config[CONF_RGB_ORDER])) cg.add(var.set_rgb_order(config[CONF_RGB_ORDER]))
cg.add(var.set_is_rgbw(config[CONF_IS_RGBW])) cg.add(var.set_is_rgbw(config[CONF_IS_RGBW]))
cg.add(var.set_is_wrgb(config[CONF_IS_WRGB]))
cg.add( cg.add(
var.set_rmt_channel( var.set_rmt_channel(

View File

@ -4,6 +4,7 @@ from esphome.const import (
KEY_TARGET_FRAMEWORK, KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM, KEY_TARGET_PLATFORM,
PLATFORM_HOST, PLATFORM_HOST,
CONF_MAC_ADDRESS,
) )
from esphome.core import CORE from esphome.core import CORE
from esphome.helpers import IS_MACOS from esphome.helpers import IS_MACOS
@ -28,13 +29,18 @@ def set_core_data(config):
CONFIG_SCHEMA = cv.All( CONFIG_SCHEMA = cv.All(
cv.Schema({}), cv.Schema(
{
cv.Optional(CONF_MAC_ADDRESS, default="98:35:69:ab:f6:79"): cv.mac_address,
}
),
set_core_data, set_core_data,
) )
async def to_code(config): async def to_code(config):
cg.add_build_flag("-DUSE_HOST") cg.add_build_flag("-DUSE_HOST")
cg.add_define("USE_ESPHOME_HOST_MAC_ADDRESS", config[CONF_MAC_ADDRESS].parts)
cg.add_build_flag("-std=c++17") cg.add_build_flag("-std=c++17")
cg.add_build_flag("-lsodium") cg.add_build_flag("-lsodium")
if IS_MACOS: if IS_MACOS:

View File

@ -120,6 +120,7 @@ void LightState::loop() {
// Apply transformer (if any) // Apply transformer (if any)
if (this->transformer_ != nullptr) { if (this->transformer_ != nullptr) {
auto values = this->transformer_->apply(); auto values = this->transformer_->apply();
this->is_transformer_active_ = true;
if (values.has_value()) { if (values.has_value()) {
this->current_values = *values; this->current_values = *values;
this->output_->update_state(this); this->output_->update_state(this);
@ -131,6 +132,7 @@ void LightState::loop() {
this->current_values = this->transformer_->get_target_values(); this->current_values = this->transformer_->get_target_values();
this->transformer_->stop(); this->transformer_->stop();
this->is_transformer_active_ = false;
this->transformer_ = nullptr; this->transformer_ = nullptr;
this->target_state_reached_callback_.call(); this->target_state_reached_callback_.call();
} }
@ -214,6 +216,8 @@ void LightState::current_values_as_ct(float *color_temperature, float *white_bri
this->gamma_correct_); this->gamma_correct_);
} }
bool LightState::is_transformer_active() { return this->is_transformer_active_; }
void LightState::start_effect_(uint32_t effect_index) { void LightState::start_effect_(uint32_t effect_index) {
this->stop_effect_(); this->stop_effect_();
if (effect_index == 0) if (effect_index == 0)
@ -263,6 +267,7 @@ void LightState::start_flash_(const LightColorValues &target, uint32_t length, b
} }
void LightState::set_immediately_(const LightColorValues &target, bool set_remote_values) { void LightState::set_immediately_(const LightColorValues &target, bool set_remote_values) {
this->is_transformer_active_ = false;
this->transformer_ = nullptr; this->transformer_ = nullptr;
this->current_values = target; this->current_values = target;
if (set_remote_values) { if (set_remote_values) {

View File

@ -144,6 +144,17 @@ class LightState : public EntityBase, public Component {
void current_values_as_ct(float *color_temperature, float *white_brightness); void current_values_as_ct(float *color_temperature, float *white_brightness);
/**
* Indicator if a transformer (e.g. transition) is active. This is useful
* for effects e.g. at the start of the apply() method, add a check like:
*
* if (this->state_->is_transformer_active()) {
* // Something is already running.
* return;
* }
*/
bool is_transformer_active();
protected: protected:
friend LightOutput; friend LightOutput;
friend LightCall; friend LightCall;
@ -203,6 +214,9 @@ class LightState : public EntityBase, public Component {
LightRestoreMode restore_mode_; LightRestoreMode restore_mode_;
/// List of effects for this light. /// List of effects for this light.
std::vector<LightEffect *> effects_; std::vector<LightEffect *> effects_;
// for effects, true if a transformer (transition) is active.
bool is_transformer_active_ = false;
}; };
} // namespace light } // namespace light

View File

@ -3,6 +3,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include <vector>
namespace esphome { namespace esphome {
namespace lightwaverf { namespace lightwaverf {

View File

@ -212,6 +212,14 @@ void HOT Logger::log_message_(int level, const char *tag, int offset) {
return; return;
#endif #endif
#ifdef USE_HOST #ifdef USE_HOST
time_t rawtime;
struct tm *timeinfo;
char buffer[80];
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(buffer, sizeof buffer, "[%H:%M:%S]", timeinfo);
fputs(buffer, stdout);
puts(msg); puts(msg);
#endif #endif

View File

@ -0,0 +1,363 @@
import logging
import json
import hashlib
from urllib.parse import urljoin
from pathlib import Path
import requests
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.core import CORE, HexInt, EsphomeError
from esphome.components import esp32, microphone
from esphome import automation, git, external_files
from esphome.automation import register_action, register_condition
from esphome.const import (
__version__,
CONF_ID,
CONF_MICROPHONE,
CONF_MODEL,
CONF_URL,
CONF_FILE,
CONF_PATH,
CONF_REF,
CONF_REFRESH,
CONF_TYPE,
CONF_USERNAME,
CONF_PASSWORD,
CONF_RAW_DATA_ID,
TYPE_GIT,
TYPE_LOCAL,
)
_LOGGER = logging.getLogger(__name__)
CODEOWNERS = ["@kahrendt", "@jesserockz"]
DEPENDENCIES = ["microphone"]
DOMAIN = "micro_wake_word"
CONF_PROBABILITY_CUTOFF = "probability_cutoff"
CONF_SLIDING_WINDOW_AVERAGE_SIZE = "sliding_window_average_size"
CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected"
TYPE_HTTP = "http"
micro_wake_word_ns = cg.esphome_ns.namespace("micro_wake_word")
MicroWakeWord = micro_wake_word_ns.class_("MicroWakeWord", cg.Component)
StartAction = micro_wake_word_ns.class_("StartAction", automation.Action)
StopAction = micro_wake_word_ns.class_("StopAction", automation.Action)
IsRunningCondition = micro_wake_word_ns.class_(
"IsRunningCondition", automation.Condition
)
def _validate_json_filename(value):
value = cv.string(value)
if not value.endswith(".json"):
raise cv.Invalid("Manifest filename must end with .json")
return value
def _process_git_source(config):
repo_dir, _ = git.clone_or_update(
url=config[CONF_URL],
ref=config.get(CONF_REF),
refresh=config[CONF_REFRESH],
domain=DOMAIN,
username=config.get(CONF_USERNAME),
password=config.get(CONF_PASSWORD),
)
if not (repo_dir / config[CONF_FILE]).exists():
raise cv.Invalid("File does not exist in repository")
return config
CV_GIT_SCHEMA = cv.GIT_SCHEMA
if isinstance(CV_GIT_SCHEMA, dict):
CV_GIT_SCHEMA = cv.Schema(CV_GIT_SCHEMA)
GIT_SCHEMA = cv.All(
CV_GIT_SCHEMA.extend(
{
cv.Required(CONF_FILE): _validate_json_filename,
cv.Optional(CONF_REFRESH, default="1d"): cv.All(
cv.string, cv.source_refresh
),
}
),
_process_git_source,
)
KEY_WAKE_WORD = "wake_word"
KEY_AUTHOR = "author"
KEY_WEBSITE = "website"
KEY_VERSION = "version"
KEY_MICRO = "micro"
MANIFEST_SCHEMA_V1 = cv.Schema(
{
cv.Required(CONF_TYPE): "micro",
cv.Required(KEY_WAKE_WORD): cv.string,
cv.Required(KEY_AUTHOR): cv.string,
cv.Required(KEY_WEBSITE): cv.url,
cv.Required(KEY_VERSION): cv.All(cv.int_, 1),
cv.Required(CONF_MODEL): cv.string,
cv.Required(KEY_MICRO): cv.Schema(
{
cv.Required(CONF_PROBABILITY_CUTOFF): cv.float_,
cv.Required(CONF_SLIDING_WINDOW_AVERAGE_SIZE): cv.positive_int,
}
),
}
)
def _compute_local_file_path(config: dict) -> Path:
url = config[CONF_URL]
h = hashlib.new("sha256")
h.update(url.encode())
key = h.hexdigest()[:8]
base_dir = external_files.compute_local_file_dir(DOMAIN)
return base_dir / key
def _download_file(url: str, path: Path) -> bytes:
if not external_files.has_remote_file_changed(url, path):
_LOGGER.debug("Remote file has not changed, skipping download")
return path.read_bytes()
try:
req = requests.get(
url,
timeout=external_files.NETWORK_TIMEOUT,
headers={"User-agent": f"ESPHome/{__version__} (https://esphome.io)"},
)
req.raise_for_status()
except requests.exceptions.RequestException as e:
raise cv.Invalid(f"Could not download file from {url}: {e}") from e
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(req.content)
return req.content
def _process_http_source(config):
url = config[CONF_URL]
path = _compute_local_file_path(config)
json_path = path / "manifest.json"
json_contents = _download_file(url, json_path)
manifest_data = json.loads(json_contents)
if not isinstance(manifest_data, dict):
raise cv.Invalid("Manifest file must contain a JSON object")
try:
MANIFEST_SCHEMA_V1(manifest_data)
except cv.Invalid as e:
raise cv.Invalid(f"Invalid manifest file: {e}") from e
model = manifest_data[CONF_MODEL]
model_url = urljoin(url, model)
model_path = path / model
_download_file(str(model_url), model_path)
return config
HTTP_SCHEMA = cv.All(
{
cv.Required(CONF_URL): cv.url,
},
_process_http_source,
)
LOCAL_SCHEMA = cv.Schema(
{
cv.Required(CONF_PATH): cv.All(_validate_json_filename, cv.file_),
}
)
def _validate_source_model_name(value):
if not isinstance(value, str):
raise cv.Invalid("Model name must be a string")
if value.endswith(".json"):
raise cv.Invalid("Model name must not end with .json")
return MODEL_SOURCE_SCHEMA(
{
CONF_TYPE: TYPE_HTTP,
CONF_URL: f"https://github.com/esphome/micro-wake-word-models/raw/main/models/{value}.json",
}
)
def _validate_source_shorthand(value):
if not isinstance(value, str):
raise cv.Invalid("Shorthand only for strings")
try: # Test for model name
return _validate_source_model_name(value)
except cv.Invalid:
pass
try: # Test for local path
return MODEL_SOURCE_SCHEMA({CONF_TYPE: TYPE_LOCAL, CONF_PATH: value})
except cv.Invalid:
pass
try: # Test for http url
return MODEL_SOURCE_SCHEMA({CONF_TYPE: TYPE_HTTP, CONF_URL: value})
except cv.Invalid:
pass
git_file = git.GitFile.from_shorthand(value)
conf = {
CONF_TYPE: TYPE_GIT,
CONF_URL: git_file.git_url,
CONF_FILE: git_file.filename,
}
if git_file.ref:
conf[CONF_REF] = git_file.ref
try:
return MODEL_SOURCE_SCHEMA(conf)
except cv.Invalid as e:
raise cv.Invalid(
f"Could not find file '{git_file.filename}' in the repository. Please make sure it exists."
) from e
MODEL_SOURCE_SCHEMA = cv.Any(
_validate_source_shorthand,
cv.typed_schema(
{
TYPE_GIT: GIT_SCHEMA,
TYPE_LOCAL: LOCAL_SCHEMA,
TYPE_HTTP: HTTP_SCHEMA,
}
),
msg="Not a valid model name, local path, http(s) url, or github shorthand",
)
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(MicroWakeWord),
cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone),
cv.Optional(CONF_PROBABILITY_CUTOFF): cv.percentage,
cv.Optional(CONF_SLIDING_WINDOW_AVERAGE_SIZE): cv.positive_int,
cv.Optional(CONF_ON_WAKE_WORD_DETECTED): automation.validate_automation(
single=True
),
cv.Required(CONF_MODEL): MODEL_SOURCE_SCHEMA,
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
}
).extend(cv.COMPONENT_SCHEMA),
cv.only_with_esp_idf,
)
def _load_model_data(manifest_path: Path):
with open(manifest_path, encoding="utf-8") as f:
manifest = json.load(f)
try:
MANIFEST_SCHEMA_V1(manifest)
except cv.Invalid as e:
raise EsphomeError(f"Invalid manifest file: {e}") from e
model_path = urljoin(str(manifest_path), manifest[CONF_MODEL])
with open(model_path, "rb") as f:
model = f.read()
return manifest, model
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
mic = await cg.get_variable(config[CONF_MICROPHONE])
cg.add(var.set_microphone(mic))
if on_wake_word_detection_config := config.get(CONF_ON_WAKE_WORD_DETECTED):
await automation.build_automation(
var.get_wake_word_detected_trigger(),
[(cg.std_string, "wake_word")],
on_wake_word_detection_config,
)
esp32.add_idf_component(
name="esp-tflite-micro",
repo="https://github.com/espressif/esp-tflite-micro",
)
cg.add_build_flag("-DTF_LITE_STATIC_MEMORY")
cg.add_build_flag("-DTF_LITE_DISABLE_X86_NEON")
cg.add_build_flag("-DESP_NN")
model_config = config.get(CONF_MODEL)
data = []
if model_config[CONF_TYPE] == TYPE_GIT:
# compute path to model file
key = f"{model_config[CONF_URL]}@{model_config.get(CONF_REF)}"
base_dir = Path(CORE.data_dir) / DOMAIN
h = hashlib.new("sha256")
h.update(key.encode())
file: Path = base_dir / h.hexdigest()[:8] / model_config[CONF_FILE]
elif model_config[CONF_TYPE] == TYPE_LOCAL:
file = model_config[CONF_PATH]
elif model_config[CONF_TYPE] == TYPE_HTTP:
file = _compute_local_file_path(model_config) / "manifest.json"
manifest, data = _load_model_data(file)
rhs = [HexInt(x) for x in data]
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
cg.add(var.set_model_start(prog_arr))
probability_cutoff = config.get(
CONF_PROBABILITY_CUTOFF, manifest[KEY_MICRO][CONF_PROBABILITY_CUTOFF]
)
cg.add(var.set_probability_cutoff(probability_cutoff))
sliding_window_average_size = config.get(
CONF_SLIDING_WINDOW_AVERAGE_SIZE,
manifest[KEY_MICRO][CONF_SLIDING_WINDOW_AVERAGE_SIZE],
)
cg.add(var.set_sliding_window_average_size(sliding_window_average_size))
cg.add(var.set_wake_word(manifest[KEY_WAKE_WORD]))
MICRO_WAKE_WORD_ACTION_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(MicroWakeWord)})
@register_action("micro_wake_word.start", StartAction, MICRO_WAKE_WORD_ACTION_SCHEMA)
@register_action("micro_wake_word.stop", StopAction, MICRO_WAKE_WORD_ACTION_SCHEMA)
@register_condition(
"micro_wake_word.is_running", IsRunningCondition, MICRO_WAKE_WORD_ACTION_SCHEMA
)
async def micro_wake_word_action_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var

View File

@ -0,0 +1,493 @@
#pragma once
#ifdef USE_ESP_IDF
// Converted audio_preprocessor_int8.tflite
// From https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/micro/examples/micro_speech/models accessed
// January 2024
//
// Copyright 2023 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace esphome {
namespace micro_wake_word {
const unsigned char G_AUDIO_PREPROCESSOR_INT8_TFLITE[] = {
0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x14, 0x00, 0x20, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10,
0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x88, 0x00,
0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, 0xcc, 0x1f, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe2, 0xeb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00,
0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67,
0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x94, 0xff,
0xff, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x70, 0x75,
0x74, 0x5f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc2, 0xf5, 0xff, 0xff,
0x04, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65,
0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xdc, 0xff, 0xff, 0xff, 0x2d, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f,
0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00,
0x08, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6e,
0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x2e, 0x00,
0x00, 0x00, 0x9c, 0x0d, 0x00, 0x00, 0x94, 0x0d, 0x00, 0x00, 0xc4, 0x09, 0x00, 0x00, 0x6c, 0x09, 0x00, 0x00, 0x48,
0x09, 0x00, 0x00, 0x34, 0x09, 0x00, 0x00, 0x20, 0x09, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x00, 0xf8, 0x08, 0x00, 0x00,
0xec, 0x07, 0x00, 0x00, 0x88, 0x07, 0x00, 0x00, 0x24, 0x07, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x38, 0x04, 0x00,
0x00, 0xb0, 0x01, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x60, 0x01,
0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x2c,
0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00,
0x04, 0x01, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00,
0x00, 0xdc, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0xbc, 0x00,
0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x94,
0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf2, 0xf6, 0xff, 0xff,
0x04, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04,
0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00,
0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0a, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x2e, 0x31, 0x32, 0x2e, 0x30, 0x00,
0x00, 0x56, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x32, 0x2e, 0x38, 0x2e, 0x30, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0xe1, 0xff, 0xff, 0xd8, 0xe1, 0xff, 0xff, 0xdc,
0xe1, 0xff, 0xff, 0xe0, 0xe1, 0xff, 0xff, 0xe4, 0xe1, 0xff, 0xff, 0xe8, 0xe1, 0xff, 0xff, 0xec, 0xe1, 0xff, 0xff,
0xf0, 0xe1, 0xff, 0xff, 0xf4, 0xe1, 0xff, 0xff, 0xf8, 0xe1, 0xff, 0xff, 0xfc, 0xe1, 0xff, 0xff, 0x00, 0xe2, 0xff,
0xff, 0x04, 0xe2, 0xff, 0xff, 0x08, 0xe2, 0xff, 0xff, 0x0c, 0xe2, 0xff, 0xff, 0x10, 0xe2, 0xff, 0xff, 0x14, 0xe2,
0xff, 0xff, 0x18, 0xe2, 0xff, 0xff, 0x1c, 0xe2, 0xff, 0xff, 0x20, 0xe2, 0xff, 0xff, 0x24, 0xe2, 0xff, 0xff, 0x28,
0xe2, 0xff, 0xff, 0x2c, 0xe2, 0xff, 0xff, 0x30, 0xe2, 0xff, 0xff, 0xd2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x9a, 0x02, 0x00, 0x00, 0xe2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0xf2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0xff,
0xff, 0xff, 0x02, 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x12,
0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x22, 0xf8, 0xff, 0xff,
0x04, 0x00, 0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x61, 0x05, 0x00, 0x00, 0x00, 0x00, 0x23, 0x0b, 0x41,
0x01, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0e, 0x80, 0x05,
0x00, 0x00, 0x00, 0x00, 0xd1, 0x0c, 0x63, 0x04, 0x00, 0x00, 0x00, 0x00, 0x34, 0x0c, 0x3f, 0x04, 0x00, 0x00, 0x00,
0x00, 0x81, 0x0c, 0xf7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0d, 0x77, 0x06, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x0f,
0xa9, 0x08, 0x01, 0x02, 0x7f, 0x0b, 0x22, 0x05, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x0e, 0xd1, 0x08, 0xdb, 0x02, 0x00,
0x00, 0x00, 0x00, 0x03, 0x0d, 0x4a, 0x07, 0xad, 0x01, 0x2c, 0x0c, 0xc6, 0x06, 0x79, 0x01, 0x00, 0x00, 0x00, 0x00,
0x45, 0x0c, 0x29, 0x07, 0x23, 0x02, 0x34, 0x0d, 0x5b, 0x08, 0x96, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x0e, 0x48,
0x0a, 0xbd, 0x05, 0x45, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x0c, 0x88, 0x08, 0x43, 0x04,
0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x0b, 0xd3, 0x07, 0xcb, 0x03, 0xd2, 0x0f, 0xe7,
0x0b, 0x09, 0x08, 0x39, 0x04, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x0c, 0x14, 0x09,
0x75, 0x05, 0xe2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x0e, 0xdd, 0x0a, 0x6b, 0x07, 0x03,
0x04, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x0d, 0x09, 0x0a, 0xc9, 0x06, 0x93, 0x03, 0x65, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0d, 0x25, 0x0a, 0x12, 0x07, 0x07, 0x04, 0x05, 0x01, 0x00, 0x00, 0x00,
0x00, 0x0a, 0x0e, 0x17, 0x0b, 0x2c, 0x08, 0x49, 0x05, 0x6d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x98, 0x0f, 0xcb, 0x0c, 0x04, 0x0a, 0x44, 0x07, 0x8b, 0x04, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x0f, 0x87,
0x0c, 0xe7, 0x09, 0x4e, 0x07, 0xba, 0x04, 0x2d, 0x02, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x0f, 0x23, 0x0d, 0xa7, 0x0a,
0x30, 0x08, 0xbe, 0x05, 0x52, 0x03, 0xeb, 0x00, 0x89, 0x0e, 0x2c, 0x0c, 0xd4, 0x09, 0x81, 0x07, 0x33, 0x05, 0xe9,
0x02, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0e, 0x29, 0x0c, 0xf1, 0x09, 0xbe, 0x07, 0x90, 0x05, 0x65, 0x03,
0x3f, 0x01, 0x1d, 0x0f, 0xff, 0x0c, 0xe5, 0x0a, 0xcf, 0x08, 0xbc, 0x06, 0xae, 0x04, 0xa3, 0x02, 0x9c, 0x00, 0x99,
0x0e, 0x99, 0x0c, 0x9d, 0x0a, 0xa4, 0x08, 0xaf, 0x06, 0xbd, 0x04, 0xcf, 0x02, 0xe4, 0x00, 0xfc, 0x0e, 0x17, 0x0d,
0x36, 0x0b, 0x57, 0x09, 0x7c, 0x07, 0xa4, 0x05, 0xcf, 0x03, 0xfd, 0x01, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x62, 0x0e, 0x98, 0x0c, 0xd2, 0x0a, 0x0e, 0x09, 0x4d, 0x07, 0x8f, 0x05, 0xd4, 0x03, 0x1b, 0x02,
0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x0e, 0x00, 0x0d, 0x52, 0x0b, 0xa6, 0x09, 0xfd, 0x07, 0x56, 0x06, 0xb1,
0x04, 0x0f, 0x03, 0x6f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x0f, 0x37, 0x0e, 0x9e, 0x0c,
0x08, 0x0b, 0x73, 0x09, 0xe1, 0x07, 0x52, 0x06, 0xc4, 0x04, 0x38, 0x03, 0xaf, 0x01, 0x28, 0x00, 0xa3, 0x0e, 0x1f,
0x0d, 0x9e, 0x0b, 0x1f, 0x0a, 0xa2, 0x08, 0x27, 0x07, 0xae, 0x05, 0x37, 0x04, 0xc2, 0x02, 0x4e, 0x01, 0x00, 0x00,
0x00, 0x00, 0xdd, 0x0f, 0x6d, 0x0e, 0xff, 0x0c, 0x93, 0x0b, 0x29, 0x0a, 0xc1, 0x08, 0x5a, 0x07, 0xf5, 0x05, 0x92,
0x04, 0x30, 0x03, 0xd1, 0x01, 0x73, 0x00, 0x16, 0x0f, 0xbc, 0x0d, 0x62, 0x0c, 0x0b, 0x0b, 0xb5, 0x09, 0x61, 0x08,
0x0e, 0x07, 0xbd, 0x05, 0x6d, 0x04, 0x1f, 0x03, 0xd3, 0x01, 0x88, 0x00, 0x3e, 0x0f, 0xf6, 0x0d, 0xaf, 0x0c, 0x6a,
0x0b, 0x27, 0x0a, 0xe4, 0x08, 0xa3, 0x07, 0x64, 0x06, 0x26, 0x05, 0xe9, 0x03, 0xae, 0x02, 0x74, 0x01, 0x3b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0f, 0xce, 0x0d, 0x99, 0x0c, 0x66, 0x0b, 0x34, 0x0a, 0x03,
0x09, 0xd3, 0x07, 0xa5, 0x06, 0x78, 0x05, 0x4c, 0x04, 0x22, 0x03, 0xf8, 0x01, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa9, 0x0f, 0x83, 0x0e, 0x5f, 0x0d, 0x3b, 0x0c, 0x19, 0x0b, 0xf8, 0x09, 0xd8, 0x08, 0xb9, 0x07, 0x9b, 0x06, 0x7e,
0x05, 0x63, 0x04, 0x48, 0x03, 0x2f, 0x02, 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xfa, 0xff, 0xff, 0x04, 0x00,
0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x04, 0xbe, 0x0e, 0x00,
0x00, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x01, 0x7f, 0x0a, 0x00, 0x00,
0x00, 0x00, 0x2e, 0x03, 0x9c, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xcb, 0x03, 0xc0, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x7e,
0x03, 0x08, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x88, 0x09, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x56, 0x07,
0xfe, 0x0d, 0x80, 0x04, 0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x16, 0x01, 0x2e, 0x07, 0x24, 0x0d, 0x00, 0x00, 0x00,
0x00, 0xfc, 0x02, 0xb5, 0x08, 0x52, 0x0e, 0xd3, 0x03, 0x39, 0x09, 0x86, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xba, 0x03,
0xd6, 0x08, 0xdc, 0x0d, 0xcb, 0x02, 0xa4, 0x07, 0x69, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x01, 0xb7, 0x05, 0x42,
0x0a, 0xba, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x03, 0x77, 0x07, 0xbc, 0x0b, 0xf1, 0x0f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x04, 0x2c, 0x08, 0x34, 0x0c, 0x2d, 0x00, 0x18, 0x04, 0xf6,
0x07, 0xc6, 0x0b, 0x89, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0xeb, 0x06, 0x8a, 0x0a,
0x1d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x01, 0x22, 0x05, 0x94, 0x08, 0xfc, 0x0b, 0x59,
0x0f, 0x00, 0x00, 0x00, 0x00, 0xac, 0x02, 0xf6, 0x05, 0x36, 0x09, 0x6c, 0x0c, 0x9a, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xbe, 0x02, 0xda, 0x05, 0xed, 0x08, 0xf8, 0x0b, 0xfa, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xf5,
0x01, 0xe8, 0x04, 0xd3, 0x07, 0xb6, 0x0a, 0x92, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00,
0x34, 0x03, 0xfb, 0x05, 0xbb, 0x08, 0x74, 0x0b, 0x27, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x78, 0x03, 0x18,
0x06, 0xb1, 0x08, 0x45, 0x0b, 0xd2, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0xdc, 0x02, 0x58, 0x05, 0xcf, 0x07,
0x41, 0x0a, 0xad, 0x0c, 0x14, 0x0f, 0x76, 0x01, 0xd3, 0x03, 0x2b, 0x06, 0x7e, 0x08, 0xcc, 0x0a, 0x16, 0x0d, 0x5a,
0x0f, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x01, 0xd6, 0x03, 0x0e, 0x06, 0x41, 0x08, 0x6f, 0x0a, 0x9a, 0x0c, 0xc0, 0x0e,
0xe2, 0x00, 0x00, 0x03, 0x1a, 0x05, 0x30, 0x07, 0x43, 0x09, 0x51, 0x0b, 0x5c, 0x0d, 0x63, 0x0f, 0x66, 0x01, 0x66,
0x03, 0x62, 0x05, 0x5b, 0x07, 0x50, 0x09, 0x42, 0x0b, 0x30, 0x0d, 0x1b, 0x0f, 0x03, 0x01, 0xe8, 0x02, 0xc9, 0x04,
0xa8, 0x06, 0x83, 0x08, 0x5b, 0x0a, 0x30, 0x0c, 0x02, 0x0e, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x9d, 0x01, 0x67, 0x03, 0x2d, 0x05, 0xf1, 0x06, 0xb2, 0x08, 0x70, 0x0a, 0x2b, 0x0c, 0xe4, 0x0d, 0x9a, 0x0f,
0x00, 0x00, 0x00, 0x00, 0x4e, 0x01, 0xff, 0x02, 0xad, 0x04, 0x59, 0x06, 0x02, 0x08, 0xa9, 0x09, 0x4e, 0x0b, 0xf0,
0x0c, 0x90, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0xc8, 0x01, 0x61, 0x03, 0xf7, 0x04,
0x8c, 0x06, 0x1e, 0x08, 0xad, 0x09, 0x3b, 0x0b, 0xc7, 0x0c, 0x50, 0x0e, 0xd7, 0x0f, 0x5c, 0x01, 0xe0, 0x02, 0x61,
0x04, 0xe0, 0x05, 0x5d, 0x07, 0xd8, 0x08, 0x51, 0x0a, 0xc8, 0x0b, 0x3d, 0x0d, 0xb1, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x22, 0x00, 0x92, 0x01, 0x00, 0x03, 0x6c, 0x04, 0xd6, 0x05, 0x3e, 0x07, 0xa5, 0x08, 0x0a, 0x0a, 0x6d, 0x0b, 0xcf,
0x0c, 0x2e, 0x0e, 0x8c, 0x0f, 0xe9, 0x00, 0x43, 0x02, 0x9d, 0x03, 0xf4, 0x04, 0x4a, 0x06, 0x9e, 0x07, 0xf1, 0x08,
0x42, 0x0a, 0x92, 0x0b, 0xe0, 0x0c, 0x2c, 0x0e, 0x77, 0x0f, 0xc1, 0x00, 0x09, 0x02, 0x50, 0x03, 0x95, 0x04, 0xd8,
0x05, 0x1b, 0x07, 0x5c, 0x08, 0x9b, 0x09, 0xd9, 0x0a, 0x16, 0x0c, 0x51, 0x0d, 0x8b, 0x0e, 0xc4, 0x0f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x31, 0x02, 0x66, 0x03, 0x99, 0x04, 0xcb, 0x05, 0xfc, 0x06, 0x2c,
0x08, 0x5a, 0x09, 0x87, 0x0a, 0xb3, 0x0b, 0xdd, 0x0c, 0x07, 0x0e, 0x2f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00,
0x7c, 0x01, 0xa0, 0x02, 0xc4, 0x03, 0xe6, 0x04, 0x07, 0x06, 0x27, 0x07, 0x46, 0x08, 0x64, 0x09, 0x81, 0x0a, 0x9c,
0x0b, 0xb7, 0x0c, 0xd0, 0x0d, 0xe8, 0x0e, 0x00, 0x10, 0x00, 0x00, 0x2a, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,
0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10,
0x00, 0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1e, 0x00, 0x20, 0x00, 0x24, 0x00, 0x26, 0x00, 0x2a, 0x00,
0x2e, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3a, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x5a,
0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x92, 0x00, 0x9a, 0x00, 0xa6, 0x00,
0xb0, 0x00, 0xbc, 0x00, 0xc8, 0x00, 0xd4, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x8a, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00,
0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00,
0x1c, 0x00, 0x20, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2c, 0x00, 0x30, 0x00, 0x34, 0x00, 0x38, 0x00, 0x3c, 0x00, 0x44,
0x00, 0x4c, 0x00, 0x50, 0x00, 0x58, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00,
0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa8, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xc4, 0x00, 0xd0, 0x00, 0xdc, 0x00, 0xe8,
0x00, 0xf4, 0x00, 0x00, 0x01, 0x0c, 0x01, 0x1c, 0x01, 0x2c, 0x01, 0x00, 0x00, 0xea, 0xfd, 0xff, 0xff, 0x04, 0x00,
0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00,
0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08,
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00,
0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4a, 0xfe, 0xff, 0xff, 0x04,
0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x7c, 0x7f, 0x79, 0x7f, 0x76, 0x7f, 0xfa, 0xff, 0x00, 0x00, 0x00, 0x00,
0x70, 0x7f, 0xf4, 0xff, 0x00, 0x00, 0x00, 0x00, 0x64, 0x7f, 0xe9, 0xff, 0xfe, 0xff, 0x00, 0x00, 0x4b, 0x7f, 0xd0,
0xff, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x7f, 0xa0, 0xff, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x7e, 0x42, 0xff, 0x00, 0x00,
0x00, 0x00, 0xfd, 0x7d, 0x86, 0xfe, 0x04, 0x00, 0x00, 0x00, 0x87, 0x7c, 0x1d, 0xfd, 0x12, 0x00, 0x00, 0x00, 0xb6,
0x79, 0x7f, 0xfa, 0x3e, 0x00, 0x00, 0x00, 0x73, 0x74, 0xf9, 0xf5, 0xca, 0x00, 0x00, 0x00, 0x36, 0x6b, 0x33, 0xef,
0x32, 0x02, 0x00, 0x00, 0x9b, 0x5c, 0x87, 0xe7, 0xce, 0x04, 0x00, 0x00, 0xf0, 0x48, 0xde, 0xe2, 0xa0, 0x07, 0x00,
0x00, 0x6e, 0x33, 0x8a, 0xe4, 0xa4, 0x08, 0x00, 0x00, 0x9c, 0x20, 0x22, 0xeb, 0x4c, 0x07, 0x00, 0x00, 0x0a, 0x13,
0x7d, 0xf2, 0x02, 0x05, 0x00, 0x00, 0x89, 0x0a, 0x17, 0xf8, 0x06, 0x03, 0x00, 0x00, 0xa6, 0x05, 0xa0, 0xfb, 0xb4,
0x01, 0x00, 0x00, 0xfa, 0x02, 0xac, 0xfd, 0xe8, 0x00, 0x00, 0x00, 0x8e, 0x01, 0xc7, 0xfe, 0x7a, 0x00, 0x00, 0x00,
0xcf, 0x00, 0x5c, 0xff, 0x40, 0x00, 0x00, 0x00, 0x6b, 0x00, 0xab, 0xff, 0x22, 0x00, 0x00, 0x00, 0x38, 0x00, 0xd3,
0xff, 0x12, 0x00, 0x00, 0x00, 0x1d, 0x00, 0xea, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xf3, 0xff, 0x06, 0x00,
0x00, 0x00, 0x08, 0x00, 0xf8, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0xfd, 0xff, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfd, 0xff,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x82, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00,
0x92, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0xff, 0xff, 0xff, 0x04, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x02, 0x00, 0x04, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x13, 0x00, 0x17, 0x00,
0x1b, 0x00, 0x20, 0x00, 0x25, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x35, 0x00, 0x3c, 0x00, 0x42, 0x00, 0x49, 0x00, 0x51,
0x00, 0x58, 0x00, 0x60, 0x00, 0x68, 0x00, 0x71, 0x00, 0x7a, 0x00, 0x83, 0x00, 0x8d, 0x00, 0x97, 0x00, 0xa1, 0x00,
0xac, 0x00, 0xb7, 0x00, 0xc2, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xe5, 0x00, 0xf2, 0x00, 0xff, 0x00, 0x0c, 0x01, 0x19,
0x01, 0x27, 0x01, 0x35, 0x01, 0x43, 0x01, 0x52, 0x01, 0x61, 0x01, 0x70, 0x01, 0x7f, 0x01, 0x8f, 0x01, 0x9f, 0x01,
0xaf, 0x01, 0xc0, 0x01, 0xd1, 0x01, 0xe2, 0x01, 0xf3, 0x01, 0x05, 0x02, 0x17, 0x02, 0x29, 0x02, 0x3c, 0x02, 0x4e,
0x02, 0x61, 0x02, 0x75, 0x02, 0x88, 0x02, 0x9c, 0x02, 0xb0, 0x02, 0xc4, 0x02, 0xd8, 0x02, 0xed, 0x02, 0x02, 0x03,
0x17, 0x03, 0x2c, 0x03, 0x41, 0x03, 0x57, 0x03, 0x6d, 0x03, 0x83, 0x03, 0x99, 0x03, 0xb0, 0x03, 0xc7, 0x03, 0xdd,
0x03, 0xf4, 0x03, 0x0c, 0x04, 0x23, 0x04, 0x3b, 0x04, 0x52, 0x04, 0x6a, 0x04, 0x82, 0x04, 0x9a, 0x04, 0xb3, 0x04,
0xcb, 0x04, 0xe4, 0x04, 0xfd, 0x04, 0x16, 0x05, 0x2f, 0x05, 0x48, 0x05, 0x61, 0x05, 0x7a, 0x05, 0x94, 0x05, 0xad,
0x05, 0xc7, 0x05, 0xe1, 0x05, 0xfb, 0x05, 0x15, 0x06, 0x2f, 0x06, 0x49, 0x06, 0x63, 0x06, 0x7e, 0x06, 0x98, 0x06,
0xb2, 0x06, 0xcd, 0x06, 0xe7, 0x06, 0x02, 0x07, 0x1d, 0x07, 0x37, 0x07, 0x52, 0x07, 0x6d, 0x07, 0x87, 0x07, 0xa2,
0x07, 0xbd, 0x07, 0xd8, 0x07, 0xf3, 0x07, 0x0d, 0x08, 0x28, 0x08, 0x43, 0x08, 0x5e, 0x08, 0x79, 0x08, 0x93, 0x08,
0xae, 0x08, 0xc9, 0x08, 0xe3, 0x08, 0xfe, 0x08, 0x19, 0x09, 0x33, 0x09, 0x4e, 0x09, 0x68, 0x09, 0x82, 0x09, 0x9d,
0x09, 0xb7, 0x09, 0xd1, 0x09, 0xeb, 0x09, 0x05, 0x0a, 0x1f, 0x0a, 0x39, 0x0a, 0x53, 0x0a, 0x6c, 0x0a, 0x86, 0x0a,
0x9f, 0x0a, 0xb8, 0x0a, 0xd1, 0x0a, 0xea, 0x0a, 0x03, 0x0b, 0x1c, 0x0b, 0x35, 0x0b, 0x4d, 0x0b, 0x66, 0x0b, 0x7e,
0x0b, 0x96, 0x0b, 0xae, 0x0b, 0xc5, 0x0b, 0xdd, 0x0b, 0xf4, 0x0b, 0x0c, 0x0c, 0x23, 0x0c, 0x39, 0x0c, 0x50, 0x0c,
0x67, 0x0c, 0x7d, 0x0c, 0x93, 0x0c, 0xa9, 0x0c, 0xbf, 0x0c, 0xd4, 0x0c, 0xe9, 0x0c, 0xfe, 0x0c, 0x13, 0x0d, 0x28,
0x0d, 0x3c, 0x0d, 0x50, 0x0d, 0x64, 0x0d, 0x78, 0x0d, 0x8b, 0x0d, 0x9f, 0x0d, 0xb2, 0x0d, 0xc4, 0x0d, 0xd7, 0x0d,
0xe9, 0x0d, 0xfb, 0x0d, 0x0d, 0x0e, 0x1e, 0x0e, 0x2f, 0x0e, 0x40, 0x0e, 0x51, 0x0e, 0x61, 0x0e, 0x71, 0x0e, 0x81,
0x0e, 0x90, 0x0e, 0x9f, 0x0e, 0xae, 0x0e, 0xbd, 0x0e, 0xcb, 0x0e, 0xd9, 0x0e, 0xe7, 0x0e, 0xf4, 0x0e, 0x01, 0x0f,
0x0e, 0x0f, 0x1b, 0x0f, 0x27, 0x0f, 0x33, 0x0f, 0x3e, 0x0f, 0x49, 0x0f, 0x54, 0x0f, 0x5f, 0x0f, 0x69, 0x0f, 0x73,
0x0f, 0x7d, 0x0f, 0x86, 0x0f, 0x8f, 0x0f, 0x98, 0x0f, 0xa0, 0x0f, 0xa8, 0x0f, 0xaf, 0x0f, 0xb7, 0x0f, 0xbe, 0x0f,
0xc4, 0x0f, 0xcb, 0x0f, 0xd0, 0x0f, 0xd6, 0x0f, 0xdb, 0x0f, 0xe0, 0x0f, 0xe5, 0x0f, 0xe9, 0x0f, 0xed, 0x0f, 0xf0,
0x0f, 0xf3, 0x0f, 0xf6, 0x0f, 0xf9, 0x0f, 0xfb, 0x0f, 0xfc, 0x0f, 0xfe, 0x0f, 0xff, 0x0f, 0x00, 0x10, 0x00, 0x10,
0x00, 0x10, 0x00, 0x10, 0xff, 0x0f, 0xfe, 0x0f, 0xfc, 0x0f, 0xfb, 0x0f, 0xf9, 0x0f, 0xf6, 0x0f, 0xf3, 0x0f, 0xf0,
0x0f, 0xed, 0x0f, 0xe9, 0x0f, 0xe5, 0x0f, 0xe0, 0x0f, 0xdb, 0x0f, 0xd6, 0x0f, 0xd0, 0x0f, 0xcb, 0x0f, 0xc4, 0x0f,
0xbe, 0x0f, 0xb7, 0x0f, 0xaf, 0x0f, 0xa8, 0x0f, 0xa0, 0x0f, 0x98, 0x0f, 0x8f, 0x0f, 0x86, 0x0f, 0x7d, 0x0f, 0x73,
0x0f, 0x69, 0x0f, 0x5f, 0x0f, 0x54, 0x0f, 0x49, 0x0f, 0x3e, 0x0f, 0x33, 0x0f, 0x27, 0x0f, 0x1b, 0x0f, 0x0e, 0x0f,
0x01, 0x0f, 0xf4, 0x0e, 0xe7, 0x0e, 0xd9, 0x0e, 0xcb, 0x0e, 0xbd, 0x0e, 0xae, 0x0e, 0x9f, 0x0e, 0x90, 0x0e, 0x81,
0x0e, 0x71, 0x0e, 0x61, 0x0e, 0x51, 0x0e, 0x40, 0x0e, 0x2f, 0x0e, 0x1e, 0x0e, 0x0d, 0x0e, 0xfb, 0x0d, 0xe9, 0x0d,
0xd7, 0x0d, 0xc4, 0x0d, 0xb2, 0x0d, 0x9f, 0x0d, 0x8b, 0x0d, 0x78, 0x0d, 0x64, 0x0d, 0x50, 0x0d, 0x3c, 0x0d, 0x28,
0x0d, 0x13, 0x0d, 0xfe, 0x0c, 0xe9, 0x0c, 0xd4, 0x0c, 0xbf, 0x0c, 0xa9, 0x0c, 0x93, 0x0c, 0x7d, 0x0c, 0x67, 0x0c,
0x50, 0x0c, 0x39, 0x0c, 0x23, 0x0c, 0x0c, 0x0c, 0xf4, 0x0b, 0xdd, 0x0b, 0xc5, 0x0b, 0xae, 0x0b, 0x96, 0x0b, 0x7e,
0x0b, 0x66, 0x0b, 0x4d, 0x0b, 0x35, 0x0b, 0x1c, 0x0b, 0x03, 0x0b, 0xea, 0x0a, 0xd1, 0x0a, 0xb8, 0x0a, 0x9f, 0x0a,
0x86, 0x0a, 0x6c, 0x0a, 0x53, 0x0a, 0x39, 0x0a, 0x1f, 0x0a, 0x05, 0x0a, 0xeb, 0x09, 0xd1, 0x09, 0xb7, 0x09, 0x9d,
0x09, 0x82, 0x09, 0x68, 0x09, 0x4e, 0x09, 0x33, 0x09, 0x19, 0x09, 0xfe, 0x08, 0xe3, 0x08, 0xc9, 0x08, 0xae, 0x08,
0x93, 0x08, 0x79, 0x08, 0x5e, 0x08, 0x43, 0x08, 0x28, 0x08, 0x0d, 0x08, 0xf3, 0x07, 0xd8, 0x07, 0xbd, 0x07, 0xa2,
0x07, 0x87, 0x07, 0x6d, 0x07, 0x52, 0x07, 0x37, 0x07, 0x1d, 0x07, 0x02, 0x07, 0xe7, 0x06, 0xcd, 0x06, 0xb2, 0x06,
0x98, 0x06, 0x7e, 0x06, 0x63, 0x06, 0x49, 0x06, 0x2f, 0x06, 0x15, 0x06, 0xfb, 0x05, 0xe1, 0x05, 0xc7, 0x05, 0xad,
0x05, 0x94, 0x05, 0x7a, 0x05, 0x61, 0x05, 0x48, 0x05, 0x2f, 0x05, 0x16, 0x05, 0xfd, 0x04, 0xe4, 0x04, 0xcb, 0x04,
0xb3, 0x04, 0x9a, 0x04, 0x82, 0x04, 0x6a, 0x04, 0x52, 0x04, 0x3b, 0x04, 0x23, 0x04, 0x0c, 0x04, 0xf4, 0x03, 0xdd,
0x03, 0xc7, 0x03, 0xb0, 0x03, 0x99, 0x03, 0x83, 0x03, 0x6d, 0x03, 0x57, 0x03, 0x41, 0x03, 0x2c, 0x03, 0x17, 0x03,
0x02, 0x03, 0xed, 0x02, 0xd8, 0x02, 0xc4, 0x02, 0xb0, 0x02, 0x9c, 0x02, 0x88, 0x02, 0x75, 0x02, 0x61, 0x02, 0x4e,
0x02, 0x3c, 0x02, 0x29, 0x02, 0x17, 0x02, 0x05, 0x02, 0xf3, 0x01, 0xe2, 0x01, 0xd1, 0x01, 0xc0, 0x01, 0xaf, 0x01,
0x9f, 0x01, 0x8f, 0x01, 0x7f, 0x01, 0x70, 0x01, 0x61, 0x01, 0x52, 0x01, 0x43, 0x01, 0x35, 0x01, 0x27, 0x01, 0x19,
0x01, 0x0c, 0x01, 0xff, 0x00, 0xf2, 0x00, 0xe5, 0x00, 0xd9, 0x00, 0xcd, 0x00, 0xc2, 0x00, 0xb7, 0x00, 0xac, 0x00,
0xa1, 0x00, 0x97, 0x00, 0x8d, 0x00, 0x83, 0x00, 0x7a, 0x00, 0x71, 0x00, 0x68, 0x00, 0x60, 0x00, 0x58, 0x00, 0x51,
0x00, 0x49, 0x00, 0x42, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x30, 0x00, 0x2a, 0x00, 0x25, 0x00, 0x20, 0x00, 0x1b, 0x00,
0x17, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x05, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0xee, 0xff, 0xff, 0x38, 0xee, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x4d, 0x4c,
0x49, 0x52, 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xf4, 0x05, 0x00, 0x00, 0xf8, 0x05, 0x00,
0x00, 0xfc, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00,
0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x68, 0x05, 0x00, 0x00, 0x24, 0x05, 0x00, 0x00, 0xc8, 0x04, 0x00, 0x00, 0x70,
0x04, 0x00, 0x00, 0x4c, 0x04, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0xc8, 0x03, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00,
0x4c, 0x03, 0x00, 0x00, 0x14, 0x03, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, 0x6c, 0x01, 0x00,
0x00, 0x48, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x78, 0x00,
0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf6, 0xfa, 0xff, 0xff, 0x0c,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x16, 0xfb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3a, 0xfb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0xa6, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x10, 0x00, 0x00,
0x00, 0x14, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x68, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xd6, 0xfc, 0xff, 0xff, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
0x98, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00,
0x00, 0x12, 0x00, 0x00, 0x00, 0x06, 0xfd, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x10, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xc8, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x25,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x36, 0xfd, 0xff, 0xff,
0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
0x00, 0xf8, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00,
0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x84, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
0x00, 0x30, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x00, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x73, 0x63, 0x61, 0x6c,
0x65, 0x00, 0x02, 0x24, 0x0f, 0x02, 0x01, 0x02, 0x03, 0x40, 0x04, 0x04, 0x04, 0x24, 0x01, 0x01, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xdc, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00,
0x00, 0x24, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x73, 0x6e,
0x72, 0x5f, 0x73, 0x68, 0x69, 0x66, 0x74, 0x00, 0x01, 0x0b, 0x01, 0x01, 0x01, 0x06, 0x04, 0x02, 0x24, 0x01, 0x01,
0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x20, 0xfd, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00,
0x00, 0x0a, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x5f,
0x6f, 0x6e, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x5f, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67,
0x00, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e,
0x67, 0x00, 0x63, 0x6c, 0x61, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x00, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e,
0x61, 0x6c, 0x5f, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x00, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68,
0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x00, 0x6f, 0x6e, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x5f, 0x73, 0x6d,
0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x00, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x00, 0x73,
0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x00, 0x73, 0x70, 0x65, 0x63, 0x74,
0x72, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x74,
0x73, 0x00, 0x09, 0xa5, 0x88, 0x75, 0x6d, 0x59, 0x4d, 0x3a, 0x31, 0x23, 0x09, 0x00, 0x01, 0x00, 0x09, 0x00, 0x29,
0x3c, 0xd7, 0x03, 0x00, 0x00, 0x33, 0x03, 0x28, 0x00, 0x67, 0x3e, 0x99, 0x01, 0x0a, 0x00, 0x0e, 0x00, 0x05, 0x05,
0x69, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1b, 0x25, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0xfe, 0xff, 0xff, 0x10, 0x00,
0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x1d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x54, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00,
0x00, 0x2c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68,
0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x00, 0x01, 0x0e, 0x01, 0x01, 0x01, 0x28, 0x04, 0x02, 0x24, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x62, 0xfe, 0xff,
0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0xca, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8c, 0xf2, 0xff, 0xff,
0x01, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0b, 0x00,
0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd0, 0xf2, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
0x00, 0xfe, 0xfe, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x64, 0xff, 0xff, 0xff, 0x10,
0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
0x65, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x00, 0x02, 0x17, 0x0e, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0xf1, 0x00, 0x05, 0x00, 0x05, 0x05,
0x06, 0x25, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17,
0x00, 0x00, 0x00, 0xb8, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x66, 0x66, 0x74, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74,
0x68, 0x00, 0x02, 0x0e, 0x0d, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x02, 0x05, 0x05, 0x06, 0x25,
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x10,
0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08,
0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00,
0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00,
0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x73,
0x68, 0x69, 0x66, 0x74, 0x00, 0x01, 0x07, 0x01, 0x01, 0x01, 0x0c, 0x04, 0x02, 0x24, 0x01, 0x01, 0x00, 0x00, 0x00,
0x13, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x2a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xc4, 0x0a,
0x00, 0x00, 0x74, 0x0a, 0x00, 0x00, 0x3c, 0x0a, 0x00, 0x00, 0x04, 0x0a, 0x00, 0x00, 0xd0, 0x09, 0x00, 0x00, 0x88,
0x09, 0x00, 0x00, 0x40, 0x09, 0x00, 0x00, 0xfc, 0x08, 0x00, 0x00, 0xb8, 0x08, 0x00, 0x00, 0x6c, 0x08, 0x00, 0x00,
0x20, 0x08, 0x00, 0x00, 0xd4, 0x07, 0x00, 0x00, 0x88, 0x07, 0x00, 0x00, 0x3c, 0x07, 0x00, 0x00, 0xf8, 0x06, 0x00,
0x00, 0xb8, 0x06, 0x00, 0x00, 0x84, 0x06, 0x00, 0x00, 0x50, 0x06, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x00, 0xd8, 0x05,
0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x58, 0x05, 0x00, 0x00, 0x14, 0x05, 0x00, 0x00, 0xd8, 0x04, 0x00, 0x00, 0x98,
0x04, 0x00, 0x00, 0x60, 0x04, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xb0, 0x03, 0x00, 0x00,
0x6c, 0x03, 0x00, 0x00, 0x1c, 0x03, 0x00, 0x00, 0xc4, 0x02, 0x00, 0x00, 0x68, 0x02, 0x00, 0x00, 0x2c, 0x02, 0x00,
0x00, 0xe4, 0x01, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x08, 0x01,
0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xfe,
0xf5, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x00, 0x44, 0xf5, 0xff, 0xff, 0x11, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72,
0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x43, 0x61, 0x6c, 0x6c, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3e, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x84, 0xf5, 0xff, 0xff,
0x0d, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x7a, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0xc0,
0xf5, 0xff, 0xff, 0x15, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00,
0x00, 0xbe, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x04, 0xf6, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x61,
0x64, 0x64, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf2, 0xf6, 0xff, 0xff,
0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x18, 0x00, 0x00, 0x00, 0x38, 0xf6, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61,
0x74, 0x65, 0x44, 0x69, 0x76, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2a, 0xf7, 0xff, 0xff, 0x00,
0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x10, 0x00, 0x00, 0x00, 0x70, 0xf6, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x61, 0x64, 0x64, 0x00, 0x01, 0x00, 0x00,
0x00, 0x28, 0x00, 0x00, 0x00, 0x5a, 0xf7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00,
0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0xa0, 0xf6, 0xff, 0xff, 0x03,
0x00, 0x00, 0x00, 0x6d, 0x75, 0x6c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x8a, 0xf7, 0xff, 0xff,
0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x14, 0x00, 0x00, 0x00, 0xd0, 0xf6, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73, 0x74, 0x5f, 0x32,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xbe, 0xf7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14,
0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x24, 0x00, 0x00, 0x00,
0x04, 0xf7, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74,
0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x02, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x22,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x18, 0x00, 0x00, 0x00, 0x48, 0xf7, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00,
0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x63, 0x61, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00,
0x00, 0x3a, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x21, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x38, 0x00, 0x00, 0x00, 0x80, 0xf7, 0xff, 0xff, 0x28, 0x00, 0x00, 0x00, 0x73,
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x73,
0x70, 0x65, 0x63, 0x74, 0x72, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x31, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x92, 0xf8, 0xff, 0xff, 0x00, 0x00,
0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x34,
0x00, 0x00, 0x00, 0xd8, 0xf7, 0xff, 0xff, 0x27, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66,
0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x72, 0x61, 0x6c,
0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0xe6, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x2c, 0x00, 0x00, 0x00, 0x2c, 0xf8, 0xff, 0xff, 0x1e, 0x00, 0x00, 0x00,
0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f,
0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x32, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x78, 0xf8, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00,
0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x72, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x14, 0x00, 0x00, 0x00, 0xb8,
0xf8, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x01, 0x00, 0x00, 0xa6, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xec, 0xf8, 0xff, 0xff, 0x06, 0x00,
0x00, 0x00, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0xda,
0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x20, 0xf9, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72,
0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xec, 0x00,
0x00, 0x00, 0x16, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1a,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x5c, 0xf9, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,
0x43, 0x61, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x4a, 0xfa, 0xff,
0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0x1c, 0x00, 0x00, 0x00, 0x90, 0xf9, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61,
0x6c, 0x5f, 0x65, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
0x86, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xf9, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x73, 0x69,
0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x66, 0x66, 0x74, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0xbe,
0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0x04, 0xfa, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67,
0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x66, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x31,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x24, 0x00, 0x00, 0x00, 0x44, 0xfa, 0xff, 0xff,
0x15, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x66, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x6f,
0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x42, 0xfb,
0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x14, 0x00, 0x00, 0x00, 0x88, 0xfa, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x52, 0x65, 0x73, 0x68,
0x61, 0x70, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x76, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00,
0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1c, 0x00,
0x00, 0x00, 0xbc, 0xfa, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x77, 0x69,
0x6e, 0x64, 0x6f, 0x77, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
0xb6, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xfc, 0xfa, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x43, 0x6f,
0x6e, 0x73, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14,
0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00,
0x2c, 0xfb, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x16, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x11, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x5c, 0xfb, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x43,
0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00,
0x00, 0x8c, 0xfb, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x52, 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x73, 0x68,
0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82, 0xfc, 0xff, 0xff, 0x00,
0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x24, 0x00, 0x00, 0x00, 0xc8, 0xfb, 0xff, 0xff, 0x17, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79,
0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x2f, 0x79, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc2, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x08, 0xfc, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00,
0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f,
0x43, 0x6f, 0x6e, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x0a, 0xfd,
0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x50, 0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e,
0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73,
0x74, 0x5f, 0x31, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x52, 0xfd, 0xff, 0xff, 0x00, 0x00,
0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28,
0x00, 0x00, 0x00, 0x98, 0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66,
0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x32, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x9a, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0xe0,
0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65,
0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x33, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x29, 0x00, 0x00, 0x00, 0xe2, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00,
0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x28, 0xfd, 0xff, 0xff, 0x1a,
0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61,
0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x34, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00,
0x00, 0x2a, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00, 0x00, 0x70, 0xfd, 0xff, 0xff, 0x11, 0x00, 0x00, 0x00, 0x73,
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x63, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x6a, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00,
0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0xb0, 0xfd,
0xff, 0xff, 0x13, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65,
0x2f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xaa, 0xfe, 0xff, 0xff,
0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x24, 0x00, 0x00, 0x00, 0xf0, 0xfd, 0xff, 0xff, 0x15, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65,
0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xee, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0x34, 0xfe, 0xff,
0xff, 0x15, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2f,
0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x78, 0xfe, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73,
0x74, 0x5f, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xa8,
0xfe, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x96, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xdc, 0xfe, 0xff, 0xff, 0x07, 0x00,
0x00, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x73, 0x5f, 0x31, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xca,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0x14, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e,
0x73, 0x74, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x1c, 0x00,
0x18, 0x00, 0x17, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x16,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0x2c, 0x00, 0x00, 0x00, 0x5c, 0xff, 0xff, 0xff, 0x1d, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72,
0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f,
0x66, 0x72, 0x61, 0x6d, 0x65, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0,
0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00,
0xa4, 0x01, 0x00, 0x00, 0x7c, 0x01, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00,
0x00, 0x10, 0x01, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x50, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x50, 0xfe, 0xff, 0xff, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x5c, 0xfe, 0xff, 0xff,
0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x68, 0xfe, 0xff, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2a, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7c, 0xfe, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x12, 0x70, 0xfe, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x13,
0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b,
0x4c, 0x6f, 0x67, 0x00, 0x98, 0xfe, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x0a, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x50, 0x43, 0x41, 0x4e, 0x00, 0x00, 0xb8, 0xfe,
0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x23, 0x00, 0x00, 0x00, 0x53,
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b, 0x53, 0x70, 0x65, 0x63,
0x74, 0x72, 0x61, 0x6c, 0x53, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0xf0, 0xfe, 0xff,
0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1a, 0x00, 0x00, 0x00, 0x53, 0x69,
0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b, 0x53, 0x71, 0x75, 0x61, 0x72,
0x65, 0x52, 0x6f, 0x6f, 0x74, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65,
0x72, 0x42, 0x61, 0x6e, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x6c, 0xff, 0xff, 0xff, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x0c, 0x00, 0x10, 0x00, 0x0f,
0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x35, 0x7c, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x0c, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x45, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x00, 0x00,
0x00, 0x00, 0xa0, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0a,
0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x66, 0x66, 0x74, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x12, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67,
0x6e, 0x61, 0x6c, 0x46, 0x66, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x00, 0x00, 0x0c, 0x00,
0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x16, 0x0c, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0c, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67,
0x6e, 0x61, 0x6c, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x00, 0x00, 0x00, 0x00};
} // namespace micro_wake_word
} // namespace esphome
#endif // USE_ESP_IDF

View File

@ -0,0 +1,521 @@
#include "micro_wake_word.h"
/**
* This is a workaround until we can figure out a way to get
* the tflite-micro idf component code available in CI
*
* */
//
#ifndef CLANG_TIDY
#ifdef USE_ESP_IDF
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include "audio_preprocessor_int8_model_data.h"
#include <tensorflow/lite/core/c/common.h>
#include <tensorflow/lite/micro/micro_interpreter.h>
#include <tensorflow/lite/micro/micro_mutable_op_resolver.h>
#include <cmath>
namespace esphome {
namespace micro_wake_word {
static const char *const TAG = "micro_wake_word";
static const size_t SAMPLE_RATE_HZ = 16000; // 16 kHz
static const size_t BUFFER_LENGTH = 500; // 0.5 seconds
static const size_t BUFFER_SIZE = SAMPLE_RATE_HZ / 1000 * BUFFER_LENGTH;
static const size_t INPUT_BUFFER_SIZE = 32 * SAMPLE_RATE_HZ / 1000; // 32ms * 16kHz / 1000ms
float MicroWakeWord::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
static const LogString *micro_wake_word_state_to_string(State state) {
switch (state) {
case State::IDLE:
return LOG_STR("IDLE");
case State::START_MICROPHONE:
return LOG_STR("START_MICROPHONE");
case State::STARTING_MICROPHONE:
return LOG_STR("STARTING_MICROPHONE");
case State::DETECTING_WAKE_WORD:
return LOG_STR("DETECTING_WAKE_WORD");
case State::STOP_MICROPHONE:
return LOG_STR("STOP_MICROPHONE");
case State::STOPPING_MICROPHONE:
return LOG_STR("STOPPING_MICROPHONE");
default:
return LOG_STR("UNKNOWN");
}
}
void MicroWakeWord::dump_config() {
ESP_LOGCONFIG(TAG, "microWakeWord:");
ESP_LOGCONFIG(TAG, " Wake Word: %s", this->get_wake_word().c_str());
ESP_LOGCONFIG(TAG, " Probability cutoff: %.3f", this->probability_cutoff_);
ESP_LOGCONFIG(TAG, " Sliding window size: %d", this->sliding_window_average_size_);
}
void MicroWakeWord::setup() {
ESP_LOGCONFIG(TAG, "Setting up microWakeWord...");
if (!this->initialize_models()) {
ESP_LOGE(TAG, "Failed to initialize models");
this->mark_failed();
return;
}
ExternalRAMAllocator<int16_t> allocator(ExternalRAMAllocator<int16_t>::ALLOW_FAILURE);
this->input_buffer_ = allocator.allocate(INPUT_BUFFER_SIZE * sizeof(int16_t));
if (this->input_buffer_ == nullptr) {
ESP_LOGW(TAG, "Could not allocate input buffer");
this->mark_failed();
return;
}
this->ring_buffer_ = RingBuffer::create(BUFFER_SIZE * sizeof(int16_t));
if (this->ring_buffer_ == nullptr) {
ESP_LOGW(TAG, "Could not allocate ring buffer");
this->mark_failed();
return;
}
ESP_LOGCONFIG(TAG, "Micro Wake Word initialized");
}
int MicroWakeWord::read_microphone_() {
size_t bytes_read = this->microphone_->read(this->input_buffer_, INPUT_BUFFER_SIZE * sizeof(int16_t));
if (bytes_read == 0) {
return 0;
}
size_t bytes_written = this->ring_buffer_->write((void *) this->input_buffer_, bytes_read);
if (bytes_written != bytes_read) {
ESP_LOGW(TAG, "Failed to write some data to ring buffer (written=%d, expected=%d)", bytes_written, bytes_read);
}
return bytes_written;
}
void MicroWakeWord::loop() {
switch (this->state_) {
case State::IDLE:
break;
case State::START_MICROPHONE:
ESP_LOGD(TAG, "Starting Microphone");
this->microphone_->start();
this->set_state_(State::STARTING_MICROPHONE);
this->high_freq_.start();
break;
case State::STARTING_MICROPHONE:
if (this->microphone_->is_running()) {
this->set_state_(State::DETECTING_WAKE_WORD);
}
break;
case State::DETECTING_WAKE_WORD:
this->read_microphone_();
if (this->detect_wake_word_()) {
ESP_LOGD(TAG, "Wake Word Detected");
this->detected_ = true;
this->set_state_(State::STOP_MICROPHONE);
}
break;
case State::STOP_MICROPHONE:
ESP_LOGD(TAG, "Stopping Microphone");
this->microphone_->stop();
this->set_state_(State::STOPPING_MICROPHONE);
this->high_freq_.stop();
break;
case State::STOPPING_MICROPHONE:
if (this->microphone_->is_stopped()) {
this->set_state_(State::IDLE);
if (this->detected_) {
this->detected_ = false;
this->wake_word_detected_trigger_->trigger("");
}
}
break;
}
}
void MicroWakeWord::start() {
if (this->is_failed()) {
ESP_LOGW(TAG, "Wake word component is marked as failed. Please check setup logs");
return;
}
if (this->state_ != State::IDLE) {
ESP_LOGW(TAG, "Wake word is already running");
return;
}
this->set_state_(State::START_MICROPHONE);
}
void MicroWakeWord::stop() {
if (this->state_ == State::IDLE) {
ESP_LOGW(TAG, "Wake word is already stopped");
return;
}
if (this->state_ == State::STOPPING_MICROPHONE) {
ESP_LOGW(TAG, "Wake word is already stopping");
return;
}
this->set_state_(State::STOP_MICROPHONE);
}
void MicroWakeWord::set_state_(State state) {
ESP_LOGD(TAG, "State changed from %s to %s", LOG_STR_ARG(micro_wake_word_state_to_string(this->state_)),
LOG_STR_ARG(micro_wake_word_state_to_string(state)));
this->state_ = state;
}
bool MicroWakeWord::initialize_models() {
ExternalRAMAllocator<uint8_t> arena_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
ExternalRAMAllocator<int8_t> features_allocator(ExternalRAMAllocator<int8_t>::ALLOW_FAILURE);
ExternalRAMAllocator<int16_t> audio_samples_allocator(ExternalRAMAllocator<int16_t>::ALLOW_FAILURE);
this->streaming_tensor_arena_ = arena_allocator.allocate(STREAMING_MODEL_ARENA_SIZE);
if (this->streaming_tensor_arena_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate the streaming model's tensor arena.");
return false;
}
this->streaming_var_arena_ = arena_allocator.allocate(STREAMING_MODEL_VARIABLE_ARENA_SIZE);
if (this->streaming_var_arena_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate the streaming model variable's tensor arena.");
return false;
}
this->preprocessor_tensor_arena_ = arena_allocator.allocate(PREPROCESSOR_ARENA_SIZE);
if (this->preprocessor_tensor_arena_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate the audio preprocessor model's tensor arena.");
return false;
}
this->new_features_data_ = features_allocator.allocate(PREPROCESSOR_FEATURE_SIZE);
if (this->new_features_data_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate the audio features buffer.");
return false;
}
this->preprocessor_audio_buffer_ = audio_samples_allocator.allocate(SAMPLE_DURATION_COUNT);
if (this->preprocessor_audio_buffer_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate the audio preprocessor's buffer.");
return false;
}
this->preprocessor_stride_buffer_ = audio_samples_allocator.allocate(HISTORY_SAMPLES_TO_KEEP);
if (this->preprocessor_stride_buffer_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate the audio preprocessor's stride buffer.");
return false;
}
this->preprocessor_model_ = tflite::GetModel(G_AUDIO_PREPROCESSOR_INT8_TFLITE);
if (this->preprocessor_model_->version() != TFLITE_SCHEMA_VERSION) {
ESP_LOGE(TAG, "Wake word's audio preprocessor model's schema is not supported");
return false;
}
this->streaming_model_ = tflite::GetModel(this->model_start_);
if (this->streaming_model_->version() != TFLITE_SCHEMA_VERSION) {
ESP_LOGE(TAG, "Wake word's streaming model's schema is not supported");
return false;
}
static tflite::MicroMutableOpResolver<18> preprocessor_op_resolver;
static tflite::MicroMutableOpResolver<14> streaming_op_resolver;
if (!this->register_preprocessor_ops_(preprocessor_op_resolver))
return false;
if (!this->register_streaming_ops_(streaming_op_resolver))
return false;
tflite::MicroAllocator *ma =
tflite::MicroAllocator::Create(this->streaming_var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE);
this->mrv_ = tflite::MicroResourceVariables::Create(ma, 15);
static tflite::MicroInterpreter static_preprocessor_interpreter(
this->preprocessor_model_, preprocessor_op_resolver, this->preprocessor_tensor_arena_, PREPROCESSOR_ARENA_SIZE);
static tflite::MicroInterpreter static_streaming_interpreter(this->streaming_model_, streaming_op_resolver,
this->streaming_tensor_arena_,
STREAMING_MODEL_ARENA_SIZE, this->mrv_);
this->preprocessor_interperter_ = &static_preprocessor_interpreter;
this->streaming_interpreter_ = &static_streaming_interpreter;
// Allocate tensors for each models.
if (this->preprocessor_interperter_->AllocateTensors() != kTfLiteOk) {
ESP_LOGE(TAG, "Failed to allocate tensors for the audio preprocessor");
return false;
}
if (this->streaming_interpreter_->AllocateTensors() != kTfLiteOk) {
ESP_LOGE(TAG, "Failed to allocate tensors for the streaming model");
return false;
}
// Verify input tensor matches expected values
TfLiteTensor *input = this->streaming_interpreter_->input(0);
if ((input->dims->size != 3) || (input->dims->data[0] != 1) || (input->dims->data[0] != 1) ||
(input->dims->data[1] != 1) || (input->dims->data[2] != PREPROCESSOR_FEATURE_SIZE)) {
ESP_LOGE(TAG, "Wake word detection model tensor input dimensions is not 1x1x%u", input->dims->data[2]);
return false;
}
if (input->type != kTfLiteInt8) {
ESP_LOGE(TAG, "Wake word detection model tensor input is not int8.");
return false;
}
// Verify output tensor matches expected values
TfLiteTensor *output = this->streaming_interpreter_->output(0);
if ((output->dims->size != 2) || (output->dims->data[0] != 1) || (output->dims->data[1] != 1)) {
ESP_LOGE(TAG, "Wake word detection model tensor output dimensions is not 1x1.");
}
if (output->type != kTfLiteUInt8) {
ESP_LOGE(TAG, "Wake word detection model tensor input is not uint8.");
return false;
}
this->recent_streaming_probabilities_.resize(this->sliding_window_average_size_, 0.0);
return true;
}
bool MicroWakeWord::update_features_() {
// Retrieve strided audio samples
int16_t *audio_samples = nullptr;
if (!this->stride_audio_samples_(&audio_samples)) {
return false;
}
// Compute the features for the newest audio samples
if (!this->generate_single_feature_(audio_samples, SAMPLE_DURATION_COUNT, this->new_features_data_)) {
return false;
}
return true;
}
float MicroWakeWord::perform_streaming_inference_() {
TfLiteTensor *input = this->streaming_interpreter_->input(0);
size_t bytes_to_copy = input->bytes;
memcpy((void *) (tflite::GetTensorData<int8_t>(input)), (const void *) (this->new_features_data_), bytes_to_copy);
uint32_t prior_invoke = millis();
TfLiteStatus invoke_status = this->streaming_interpreter_->Invoke();
if (invoke_status != kTfLiteOk) {
ESP_LOGW(TAG, "Streaming Interpreter Invoke failed");
return false;
}
ESP_LOGV(TAG, "Streaming Inference Latency=%u ms", (millis() - prior_invoke));
TfLiteTensor *output = this->streaming_interpreter_->output(0);
return static_cast<float>(output->data.uint8[0]) / 255.0;
}
bool MicroWakeWord::detect_wake_word_() {
// Preprocess the newest audio samples into features
if (!this->update_features_()) {
return false;
}
// Perform inference
uint32_t streaming_size = micros();
float streaming_prob = this->perform_streaming_inference_();
// Add the most recent probability to the sliding window
this->recent_streaming_probabilities_[this->last_n_index_] = streaming_prob;
++this->last_n_index_;
if (this->last_n_index_ == this->sliding_window_average_size_)
this->last_n_index_ = 0;
float sum = 0.0;
for (auto &prob : this->recent_streaming_probabilities_) {
sum += prob;
}
float sliding_window_average = sum / static_cast<float>(this->sliding_window_average_size_);
// Ensure we have enough samples since the last positive detection
this->ignore_windows_ = std::min(this->ignore_windows_ + 1, 0);
if (this->ignore_windows_ < 0) {
return false;
}
// Detect the wake word if the sliding window average is above the cutoff
if (sliding_window_average > this->probability_cutoff_) {
this->ignore_windows_ = -MIN_SLICES_BEFORE_DETECTION;
for (auto &prob : this->recent_streaming_probabilities_) {
prob = 0;
}
return true;
}
return false;
}
void MicroWakeWord::set_sliding_window_average_size(size_t size) {
this->sliding_window_average_size_ = size;
this->recent_streaming_probabilities_.resize(this->sliding_window_average_size_, 0.0);
}
bool MicroWakeWord::slice_available_() {
size_t available = this->ring_buffer_->available();
size_t free = this->ring_buffer_->free();
if (free < NEW_SAMPLES_TO_GET * sizeof(int16_t)) {
// If the ring buffer is within one audio slice of being full, then wake word detection will have issues.
// If this is constantly occuring, then some possibilities why are
// 1) there are too many other slow components configured
// 2) the ESP32 isn't fast enough; e.g., an ESP32 is much slower than an ESP32-S3 at inferences.
// 3) the model is too large
// 4) the model uses operations that are not optimized
ESP_LOGW(TAG,
"Audio buffer is nearly full. Wake word detection may be less accurate and have slower reponse times. "
#if !defined(USE_ESP32_VARIANT_ESP32S3)
"microWakeWord is designed for the ESP32-S3. The current platform is too slow for this model."
#endif
);
}
return available > (NEW_SAMPLES_TO_GET * sizeof(int16_t));
}
bool MicroWakeWord::stride_audio_samples_(int16_t **audio_samples) {
if (!this->slice_available_()) {
return false;
}
// Copy 320 bytes (160 samples over 10 ms) into preprocessor_audio_buffer_ from history in
// preprocessor_stride_buffer_
memcpy((void *) (this->preprocessor_audio_buffer_), (void *) (this->preprocessor_stride_buffer_),
HISTORY_SAMPLES_TO_KEEP * sizeof(int16_t));
// Copy 640 bytes (320 samples over 20 ms) from the ring buffer
// The first 320 bytes (160 samples over 10 ms) will be from history
size_t bytes_read = this->ring_buffer_->read((void *) (this->preprocessor_audio_buffer_ + HISTORY_SAMPLES_TO_KEEP),
NEW_SAMPLES_TO_GET * sizeof(int16_t), pdMS_TO_TICKS(200));
if (bytes_read == 0) {
ESP_LOGE(TAG, "Could not read data from Ring Buffer");
} else if (bytes_read < NEW_SAMPLES_TO_GET * sizeof(int16_t)) {
ESP_LOGD(TAG, "Partial Read of Data by Model");
ESP_LOGD(TAG, "Could only read %d bytes when required %d bytes ", bytes_read,
(int) (NEW_SAMPLES_TO_GET * sizeof(int16_t)));
return false;
}
// Copy the last 320 bytes (160 samples over 10 ms) from the audio buffer into history stride buffer for the next
// iteration
memcpy((void *) (this->preprocessor_stride_buffer_), (void *) (this->preprocessor_audio_buffer_ + NEW_SAMPLES_TO_GET),
HISTORY_SAMPLES_TO_KEEP * sizeof(int16_t));
*audio_samples = this->preprocessor_audio_buffer_;
return true;
}
bool MicroWakeWord::generate_single_feature_(const int16_t *audio_data, const int audio_data_size,
int8_t feature_output[PREPROCESSOR_FEATURE_SIZE]) {
TfLiteTensor *input = this->preprocessor_interperter_->input(0);
TfLiteTensor *output = this->preprocessor_interperter_->output(0);
std::copy_n(audio_data, audio_data_size, tflite::GetTensorData<int16_t>(input));
if (this->preprocessor_interperter_->Invoke() != kTfLiteOk) {
ESP_LOGE(TAG, "Failed to preprocess audio for local wake word.");
return false;
}
std::memcpy(feature_output, tflite::GetTensorData<int8_t>(output), PREPROCESSOR_FEATURE_SIZE * sizeof(int8_t));
return true;
}
bool MicroWakeWord::register_preprocessor_ops_(tflite::MicroMutableOpResolver<18> &op_resolver) {
if (op_resolver.AddReshape() != kTfLiteOk)
return false;
if (op_resolver.AddCast() != kTfLiteOk)
return false;
if (op_resolver.AddStridedSlice() != kTfLiteOk)
return false;
if (op_resolver.AddConcatenation() != kTfLiteOk)
return false;
if (op_resolver.AddMul() != kTfLiteOk)
return false;
if (op_resolver.AddAdd() != kTfLiteOk)
return false;
if (op_resolver.AddDiv() != kTfLiteOk)
return false;
if (op_resolver.AddMinimum() != kTfLiteOk)
return false;
if (op_resolver.AddMaximum() != kTfLiteOk)
return false;
if (op_resolver.AddWindow() != kTfLiteOk)
return false;
if (op_resolver.AddFftAutoScale() != kTfLiteOk)
return false;
if (op_resolver.AddRfft() != kTfLiteOk)
return false;
if (op_resolver.AddEnergy() != kTfLiteOk)
return false;
if (op_resolver.AddFilterBank() != kTfLiteOk)
return false;
if (op_resolver.AddFilterBankSquareRoot() != kTfLiteOk)
return false;
if (op_resolver.AddFilterBankSpectralSubtraction() != kTfLiteOk)
return false;
if (op_resolver.AddPCAN() != kTfLiteOk)
return false;
if (op_resolver.AddFilterBankLog() != kTfLiteOk)
return false;
return true;
}
bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<14> &op_resolver) {
if (op_resolver.AddCallOnce() != kTfLiteOk)
return false;
if (op_resolver.AddVarHandle() != kTfLiteOk)
return false;
if (op_resolver.AddReshape() != kTfLiteOk)
return false;
if (op_resolver.AddReadVariable() != kTfLiteOk)
return false;
if (op_resolver.AddStridedSlice() != kTfLiteOk)
return false;
if (op_resolver.AddConcatenation() != kTfLiteOk)
return false;
if (op_resolver.AddAssignVariable() != kTfLiteOk)
return false;
if (op_resolver.AddConv2D() != kTfLiteOk)
return false;
if (op_resolver.AddMul() != kTfLiteOk)
return false;
if (op_resolver.AddAdd() != kTfLiteOk)
return false;
if (op_resolver.AddMean() != kTfLiteOk)
return false;
if (op_resolver.AddFullyConnected() != kTfLiteOk)
return false;
if (op_resolver.AddLogistic() != kTfLiteOk)
return false;
if (op_resolver.AddQuantize() != kTfLiteOk)
return false;
return true;
}
} // namespace micro_wake_word
} // namespace esphome
#endif // USE_ESP_IDF
#endif // CLANG_TIDY

View File

@ -0,0 +1,207 @@
#pragma once
/**
* This is a workaround until we can figure out a way to get
* the tflite-micro idf component code available in CI
*
* */
//
#ifndef CLANG_TIDY
#ifdef USE_ESP_IDF
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/ring_buffer.h"
#include "esphome/components/microphone/microphone.h"
#include <tensorflow/lite/core/c/common.h>
#include <tensorflow/lite/micro/micro_interpreter.h>
#include <tensorflow/lite/micro/micro_mutable_op_resolver.h>
namespace esphome {
namespace micro_wake_word {
// The following are dictated by the preprocessor model
//
// The number of features the audio preprocessor generates per slice
static const uint8_t PREPROCESSOR_FEATURE_SIZE = 40;
// How frequently the preprocessor generates a new set of features
static const uint8_t FEATURE_STRIDE_MS = 20;
// Duration of each slice used as input into the preprocessor
static const uint8_t FEATURE_DURATION_MS = 30;
// Audio sample frequency in hertz
static const uint16_t AUDIO_SAMPLE_FREQUENCY = 16000;
// The number of old audio samples that are saved to be part of the next feature window
static const uint16_t HISTORY_SAMPLES_TO_KEEP =
((FEATURE_DURATION_MS - FEATURE_STRIDE_MS) * (AUDIO_SAMPLE_FREQUENCY / 1000));
// The number of new audio samples to receive to be included with the next feature window
static const uint16_t NEW_SAMPLES_TO_GET = (FEATURE_STRIDE_MS * (AUDIO_SAMPLE_FREQUENCY / 1000));
// The total number of audio samples included in the feature window
static const uint16_t SAMPLE_DURATION_COUNT = FEATURE_DURATION_MS * AUDIO_SAMPLE_FREQUENCY / 1000;
// Number of bytes in memory needed for the preprocessor arena
static const uint32_t PREPROCESSOR_ARENA_SIZE = 9528;
// The following configure the streaming wake word model
//
// The number of audio slices to process before accepting a positive detection
static const uint8_t MIN_SLICES_BEFORE_DETECTION = 74;
// Number of bytes in memory needed for the streaming wake word model
static const uint32_t STREAMING_MODEL_ARENA_SIZE = 64000;
static const uint32_t STREAMING_MODEL_VARIABLE_ARENA_SIZE = 1024;
enum State {
IDLE,
START_MICROPHONE,
STARTING_MICROPHONE,
DETECTING_WAKE_WORD,
STOP_MICROPHONE,
STOPPING_MICROPHONE,
};
class MicroWakeWord : public Component {
public:
void setup() override;
void loop() override;
float get_setup_priority() const override;
void dump_config() override;
void start();
void stop();
bool is_running() const { return this->state_ != State::IDLE; }
bool initialize_models();
std::string get_wake_word() { return this->wake_word_; }
// Increasing either of these will reduce the rate of false acceptances while increasing the false rejection rate
void set_probability_cutoff(float probability_cutoff) { this->probability_cutoff_ = probability_cutoff; }
void set_sliding_window_average_size(size_t size);
void set_microphone(microphone::Microphone *microphone) { this->microphone_ = microphone; }
Trigger<std::string> *get_wake_word_detected_trigger() const { return this->wake_word_detected_trigger_; }
void set_model_start(const uint8_t *model_start) { this->model_start_ = model_start; }
void set_wake_word(const std::string &wake_word) { this->wake_word_ = wake_word; }
protected:
void set_state_(State state);
int read_microphone_();
const uint8_t *model_start_;
std::string wake_word_;
microphone::Microphone *microphone_{nullptr};
Trigger<std::string> *wake_word_detected_trigger_ = new Trigger<std::string>();
State state_{State::IDLE};
HighFrequencyLoopRequester high_freq_;
std::unique_ptr<RingBuffer> ring_buffer_;
int16_t *input_buffer_;
const tflite::Model *preprocessor_model_{nullptr};
const tflite::Model *streaming_model_{nullptr};
tflite::MicroInterpreter *streaming_interpreter_{nullptr};
tflite::MicroInterpreter *preprocessor_interperter_{nullptr};
std::vector<float> recent_streaming_probabilities_;
size_t last_n_index_{0};
float probability_cutoff_{0.5};
size_t sliding_window_average_size_{10};
// When the wake word detection first starts or after the word has been detected once, we ignore this many audio
// feature slices before accepting a positive detection again
int16_t ignore_windows_{-MIN_SLICES_BEFORE_DETECTION};
uint8_t *streaming_var_arena_{nullptr};
uint8_t *streaming_tensor_arena_{nullptr};
uint8_t *preprocessor_tensor_arena_{nullptr};
int8_t *new_features_data_{nullptr};
tflite::MicroResourceVariables *mrv_{nullptr};
// Stores audio fed into feature generator preprocessor
int16_t *preprocessor_audio_buffer_;
int16_t *preprocessor_stride_buffer_;
bool detected_{false};
/** Detects if wake word has been said
*
* If enough audio samples are available, it will generate one slice of new features.
* If the streaming model predicts the wake word, then the nonstreaming model confirms it.
* @param ring_Buffer Ring buffer containing raw audio samples
* @return True if the wake word is detected, false otherwise
*/
bool detect_wake_word_();
/// @brief Returns true if there are enough audio samples in the buffer to generate another slice of features
bool slice_available_();
/** Shifts previous feature slices over by one and generates a new slice of features
*
* @param ring_buffer ring buffer containing raw audio samples
* @return True if a new slice of features was generated, false otherwise
*/
bool update_features_();
/** Generates features from audio samples
*
* Adapted from TFLite micro speech example
* @param audio_data Pointer to array with the audio samples
* @param audio_data_size The number of samples to use as input to the preprocessor model
* @param feature_output Array that will store the features
* @return True if successful, false otherwise.
*/
bool generate_single_feature_(const int16_t *audio_data, int audio_data_size,
int8_t feature_output[PREPROCESSOR_FEATURE_SIZE]);
/** Performs inference over the most recent feature slice with the streaming model
*
* @return Probability of the wake word between 0.0 and 1.0
*/
float perform_streaming_inference_();
/** Strides the audio samples by keeping the last 10 ms of the previous slice
*
* Adapted from the TFLite micro speech example
* @param ring_buffer Ring buffer containing raw audio samples
* @param audio_samples Pointer to an array that will store the strided audio samples
* @return True if successful, false otherwise
*/
bool stride_audio_samples_(int16_t **audio_samples);
/// @brief Returns true if successfully registered the preprocessor's TensorFlow operations
bool register_preprocessor_ops_(tflite::MicroMutableOpResolver<18> &op_resolver);
/// @brief Returns true if successfully registered the streaming model's TensorFlow operations
bool register_streaming_ops_(tflite::MicroMutableOpResolver<14> &op_resolver);
};
template<typename... Ts> class StartAction : public Action<Ts...>, public Parented<MicroWakeWord> {
public:
void play(Ts... x) override { this->parent_->start(); }
};
template<typename... Ts> class StopAction : public Action<Ts...>, public Parented<MicroWakeWord> {
public:
void play(Ts... x) override { this->parent_->stop(); }
};
template<typename... Ts> class IsRunningCondition : public Condition<Ts...>, public Parented<MicroWakeWord> {
public:
bool check(Ts... x) override { return this->parent_->is_running(); }
};
} // namespace micro_wake_word
} // namespace esphome
#endif // USE_ESP_IDF
#endif // CLANG_TIDY

View File

@ -29,7 +29,8 @@ from esphome.const import (
from esphome.core import HexInt, CORE from esphome.core import HexInt, CORE
DOMAIN = "shelly_dimmer" DOMAIN = "shelly_dimmer"
DEPENDENCIES = ["sensor", "uart", "esp8266"] AUTO_LOAD = ["sensor"]
DEPENDENCIES = ["uart", "esp8266"]
shelly_dimmer_ns = cg.esphome_ns.namespace("shelly_dimmer") shelly_dimmer_ns = cg.esphome_ns.namespace("shelly_dimmer")
ShellyDimmer = shelly_dimmer_ns.class_( ShellyDimmer = shelly_dimmer_ns.class_(

View File

@ -25,6 +25,7 @@ namespace sntp {
static const char *const TAG = "sntp"; static const char *const TAG = "sntp";
void SNTPComponent::setup() { void SNTPComponent::setup() {
#ifndef USE_HOST
ESP_LOGCONFIG(TAG, "Setting up SNTP..."); ESP_LOGCONFIG(TAG, "Setting up SNTP...");
#if defined(USE_ESP32) || defined(USE_LIBRETINY) #if defined(USE_ESP32) || defined(USE_LIBRETINY)
if (sntp_enabled()) { if (sntp_enabled()) {
@ -48,6 +49,7 @@ void SNTPComponent::setup() {
#endif #endif
sntp_init(); sntp_init();
#endif
} }
void SNTPComponent::dump_config() { void SNTPComponent::dump_config() {
ESP_LOGCONFIG(TAG, "SNTP Time:"); ESP_LOGCONFIG(TAG, "SNTP Time:");
@ -57,7 +59,7 @@ void SNTPComponent::dump_config() {
ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str()); ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str());
} }
void SNTPComponent::update() { void SNTPComponent::update() {
#ifndef USE_ESP_IDF #if !defined(USE_ESP_IDF) && !defined(USE_HOST)
// force resync // force resync
if (sntp_enabled()) { if (sntp_enabled()) {
sntp_stop(); sntp_stop();

View File

@ -28,7 +28,7 @@ class Filter {
* @param value The new value. * @param value The new value.
* @return An optional string, the new value that should be pushed out. * @return An optional string, the new value that should be pushed out.
*/ */
virtual optional<std::string> new_value(std::string value); virtual optional<std::string> new_value(std::string value) = 0;
/// Initialize this filter, please note this can be called more than once. /// Initialize this filter, please note this can be called more than once.
virtual void initialize(TextSensor *parent, Filter *next); virtual void initialize(TextSensor *parent, Filter *next);

View File

@ -8,6 +8,8 @@ wled_ns = cg.esphome_ns.namespace("wled")
WLEDLightEffect = wled_ns.class_("WLEDLightEffect", AddressableLightEffect) WLEDLightEffect = wled_ns.class_("WLEDLightEffect", AddressableLightEffect)
CONFIG_SCHEMA = cv.All(cv.Schema({}), cv.only_with_arduino) CONFIG_SCHEMA = cv.All(cv.Schema({}), cv.only_with_arduino)
CONF_SYNC_GROUP_MASK = "sync_group_mask"
CONF_BLANK_ON_START = "blank_on_start"
@register_addressable_effect( @register_addressable_effect(
@ -16,10 +18,13 @@ CONFIG_SCHEMA = cv.All(cv.Schema({}), cv.only_with_arduino)
"WLED", "WLED",
{ {
cv.Optional(CONF_PORT, default=21324): cv.port, cv.Optional(CONF_PORT, default=21324): cv.port,
cv.Optional(CONF_SYNC_GROUP_MASK, default=0): cv.int_range(min=0, max=255),
cv.Optional(CONF_BLANK_ON_START, default=True): cv.boolean,
}, },
) )
async def wled_light_effect_to_code(config, effect_id): async def wled_light_effect_to_code(config, effect_id):
effect = cg.new_Pvariable(effect_id, config[CONF_NAME]) effect = cg.new_Pvariable(effect_id, config[CONF_NAME])
cg.add(effect.set_port(config[CONF_PORT])) cg.add(effect.set_port(config[CONF_PORT]))
cg.add(effect.set_sync_group_mask(config[CONF_SYNC_GROUP_MASK]))
cg.add(effect.set_blank_on_start(config[CONF_BLANK_ON_START]))
return effect return effect

View File

@ -13,6 +13,10 @@
#include <WiFiUdp.h> #include <WiFiUdp.h>
#endif #endif
#ifdef USE_BK72XX
#include <WiFiUdp.h>
#endif
namespace esphome { namespace esphome {
namespace wled { namespace wled {
@ -29,7 +33,11 @@ WLEDLightEffect::WLEDLightEffect(const std::string &name) : AddressableLightEffe
void WLEDLightEffect::start() { void WLEDLightEffect::start() {
AddressableLightEffect::start(); AddressableLightEffect::start();
blank_at_ = 0; if (this->blank_on_start_) {
this->blank_at_ = 0;
} else {
this->blank_at_ = UINT32_MAX;
}
} }
void WLEDLightEffect::stop() { void WLEDLightEffect::stop() {
@ -101,8 +109,11 @@ bool WLEDLightEffect::parse_frame_(light::AddressableLight &it, const uint8_t *p
if (!parse_drgb_frame_(it, payload, size)) if (!parse_drgb_frame_(it, payload, size))
return false; return false;
} else { } else {
if (!parse_notifier_frame_(it, payload, size)) if (!parse_notifier_frame_(it, payload, size)) {
return false; return false;
} else {
timeout = UINT8_MAX;
}
} }
break; break;
@ -143,8 +154,32 @@ bool WLEDLightEffect::parse_frame_(light::AddressableLight &it, const uint8_t *p
} }
bool WLEDLightEffect::parse_notifier_frame_(light::AddressableLight &it, const uint8_t *payload, uint16_t size) { bool WLEDLightEffect::parse_notifier_frame_(light::AddressableLight &it, const uint8_t *payload, uint16_t size) {
// Packet needs to be empty // Receive at least RGBW and Brightness for all LEDs from WLED Sync Notification
return size == 0; // https://kno.wled.ge/interfaces/udp-notifier/
// https://github.com/Aircoookie/WLED/blob/main/wled00/udp.cpp
if (size < 34) {
return false;
}
uint8_t payload_sync_group_mask = payload[34];
if (this->sync_group_mask_ && !(payload_sync_group_mask & this->sync_group_mask_)) {
ESP_LOGD(TAG, "sync group mask does not match");
return false;
}
uint8_t bri = payload[0];
uint8_t r = esp_scale8(payload[1], bri);
uint8_t g = esp_scale8(payload[2], bri);
uint8_t b = esp_scale8(payload[3], bri);
uint8_t w = esp_scale8(payload[8], bri);
for (auto &&led : it) {
led.set(Color(r, g, b, w));
}
return true;
} }
bool WLEDLightEffect::parse_warls_frame_(light::AddressableLight &it, const uint8_t *payload, uint16_t size) { bool WLEDLightEffect::parse_warls_frame_(light::AddressableLight &it, const uint8_t *payload, uint16_t size) {

View File

@ -21,6 +21,8 @@ class WLEDLightEffect : public light::AddressableLightEffect {
void stop() override; void stop() override;
void apply(light::AddressableLight &it, const Color &current_color) override; void apply(light::AddressableLight &it, const Color &current_color) override;
void set_port(uint16_t port) { this->port_ = port; } void set_port(uint16_t port) { this->port_ = port; }
void set_sync_group_mask(uint8_t mask) { this->sync_group_mask_ = mask; }
void set_blank_on_start(bool blank) { this->blank_on_start_ = blank; }
protected: protected:
void blank_all_leds_(light::AddressableLight &it); void blank_all_leds_(light::AddressableLight &it);
@ -35,6 +37,8 @@ class WLEDLightEffect : public light::AddressableLightEffect {
std::unique_ptr<UDP> udp_; std::unique_ptr<UDP> udp_;
uint32_t blank_at_{0}; uint32_t blank_at_{0};
uint32_t dropped_{0}; uint32_t dropped_{0};
uint8_t sync_group_mask_{0};
bool blank_on_start_{true};
}; };
} // namespace wled } // namespace wled

View File

@ -1,6 +1,6 @@
"""Constants used by esphome.""" """Constants used by esphome."""
__version__ = "2024.1.0-dev" __version__ = "2024.3.0-dev"
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
VALID_SUBSTITUTIONS_CHARACTERS = ( VALID_SUBSTITUTIONS_CHARACTERS = (

View File

@ -1,8 +1,9 @@
#pragma once #pragma once
#include <string>
#include <functional>
#include <cmath> #include <cmath>
#include <cstdint>
#include <functional>
#include <string>
#include "esphome/core/optional.h" #include "esphome/core/optional.h"

View File

@ -11,6 +11,12 @@
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#ifdef USE_HOST
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <unistd.h>
#endif
#if defined(USE_ESP8266) #if defined(USE_ESP8266)
#include <osapi.h> #include <osapi.h>
#include <user_interface.h> #include <user_interface.h>
@ -415,7 +421,7 @@ std::string value_accuracy_to_string(float value, int8_t accuracy_decimals) {
int8_t step_to_accuracy_decimals(float step) { int8_t step_to_accuracy_decimals(float step) {
// use printf %g to find number of digits based on temperature step // use printf %g to find number of digits based on temperature step
char buf[32]; char buf[32];
sprintf(buf, "%.5g", step); snprintf(buf, sizeof buf, "%.5g", step);
std::string str{buf}; std::string str{buf};
size_t dot_pos = str.find('.'); size_t dot_pos = str.find('.');
@ -551,7 +557,10 @@ void HighFrequencyLoopRequester::stop() {
bool HighFrequencyLoopRequester::is_high_frequency() { return num_requests > 0; } bool HighFrequencyLoopRequester::is_high_frequency() { return num_requests > 0; }
void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter)
#if defined(USE_ESP32) #if defined(USE_HOST)
static const uint8_t esphome_host_mac_address[6] = USE_ESPHOME_HOST_MAC_ADDRESS;
memcpy(mac, esphome_host_mac_address, sizeof(esphome_host_mac_address));
#elif defined(USE_ESP32)
#if defined(CONFIG_SOC_IEEE802154_SUPPORTED) || defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC) #if defined(CONFIG_SOC_IEEE802154_SUPPORTED) || defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC)
// When CONFIG_SOC_IEEE802154_SUPPORTED is defined, esp_efuse_mac_get_default // When CONFIG_SOC_IEEE802154_SUPPORTED is defined, esp_efuse_mac_get_default
// returns the 802.15.4 EUI-64 address. Read directly from eFuse instead. // returns the 802.15.4 EUI-64 address. Read directly from eFuse instead.
@ -569,6 +578,8 @@ void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parame
WiFi.macAddress(mac); WiFi.macAddress(mac);
#elif defined(USE_LIBRETINY) #elif defined(USE_LIBRETINY)
WiFi.macAddress(mac); WiFi.macAddress(mac);
#else
// this should be an error, but that messes with CI checks. #error No mac address method defined
#endif #endif
} }
std::string get_mac_address() { std::string get_mac_address() {

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <ctime> #include <ctime>
#include <string> #include <string>

View File

@ -478,7 +478,7 @@ def variable(
:param type_: Manually define a type for the variable, only use this when it's not possible :param type_: Manually define a type for the variable, only use this when it's not possible
to do so during config validation phase (for example because of template arguments). to do so during config validation phase (for example because of template arguments).
:returns The new variable as a MockObj. :return: The new variable as a MockObj.
""" """
assert isinstance(id_, ID) assert isinstance(id_, ID)
rhs = safe_exp(rhs) rhs = safe_exp(rhs)
@ -526,7 +526,7 @@ def new_variable(id_: ID, rhs: SafeExpType, type_: "MockObj" = None) -> "MockObj
:param type_: Manually define a type for the variable, only use this when it's not possible :param type_: Manually define a type for the variable, only use this when it's not possible
to do so during config validation phase (for example because of template arguments). to do so during config validation phase (for example because of template arguments).
:returns The new variable as a MockObj. :return: The new variable as a MockObj.
""" """
assert isinstance(id_, ID) assert isinstance(id_, ID)
rhs = safe_exp(rhs) rhs = safe_exp(rhs)
@ -549,7 +549,7 @@ def Pvariable(id_: ID, rhs: SafeExpType, type_: "MockObj" = None) -> "MockObj":
:param type_: Manually define a type for the variable, only use this when it's not possible :param type_: Manually define a type for the variable, only use this when it's not possible
to do so during config validation phase (for example because of template arguments). to do so during config validation phase (for example because of template arguments).
:returns The new variable as a MockObj. :return: The new variable as a MockObj.
""" """
rhs = safe_exp(rhs) rhs = safe_exp(rhs)
obj = MockObj(id_, "->") obj = MockObj(id_, "->")
@ -570,7 +570,7 @@ def new_Pvariable(id_: ID, *args: SafeExpType) -> Pvariable:
:param id_: The ID used to declare the variable (also specifies the type). :param id_: The ID used to declare the variable (also specifies the type).
:param args: The values to pass to the constructor. :param args: The values to pass to the constructor.
:returns The new variable as a MockObj. :return: The new variable as a MockObj.
""" """
if args and isinstance(args[0], TemplateArguments): if args and isinstance(args[0], TemplateArguments):
id_ = id_.copy() id_ = id_.copy()

View File

@ -1,4 +1,5 @@
async_timeout==4.0.3; python_version <= "3.10" async_timeout==4.0.3; python_version <= "3.10"
cryptography==42.0.2
voluptuous==0.14.1 voluptuous==0.14.1
PyYAML==6.0.1 PyYAML==6.0.1
paho-mqtt==1.6.1 paho-mqtt==1.6.1
@ -12,7 +13,7 @@ platformio==6.1.13 # When updating platformio, also update Dockerfile
esptool==4.7.0 esptool==4.7.0
click==8.1.7 click==8.1.7
esphome-dashboard==20231107.0 esphome-dashboard==20231107.0
aioesphomeapi==21.0.1 aioesphomeapi==21.0.2
zeroconf==0.131.0 zeroconf==0.131.0
python-magic==0.4.27 python-magic==0.4.27

View File

@ -1,3 +1,2 @@
pillow==10.2.0 pillow==10.2.0
cairosvg==2.7.1 cairosvg==2.7.1
cryptography==41.0.4

View File

@ -0,0 +1,64 @@
binary_sensor:
- platform: gpio
id: bin1
pin: 1
alarm_control_panel:
- platform: template
id: alarmcontrolpanel1
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_state:
then:
- lambda: !lambda |-
ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())));
- platform: template
id: alarmcontrolpanel2
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_disarmed:
then:
- logger.log: "### DISARMED ###"
on_pending:
then:
- logger.log: "### PENDING ###"
on_arming:
then:
- logger.log: "### ARMING ###"
on_armed_home:
then:
- logger.log: "### ARMED HOME ###"
on_armed_night:
then:
- logger.log: "### ARMED NIGHT ###"
on_armed_away:
then:
- logger.log: "### ARMED AWAY ###"
on_triggered:
then:
- logger.log: "### TRIGGERED ###"
on_cleared:
then:
- logger.log: "### CLEARED ###"

View File

@ -0,0 +1,64 @@
binary_sensor:
- platform: gpio
id: bin1
pin: 1
alarm_control_panel:
- platform: template
id: alarmcontrolpanel1
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_state:
then:
- lambda: !lambda |-
ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())));
- platform: template
id: alarmcontrolpanel2
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_disarmed:
then:
- logger.log: "### DISARMED ###"
on_pending:
then:
- logger.log: "### PENDING ###"
on_arming:
then:
- logger.log: "### ARMING ###"
on_armed_home:
then:
- logger.log: "### ARMED HOME ###"
on_armed_night:
then:
- logger.log: "### ARMED NIGHT ###"
on_armed_away:
then:
- logger.log: "### ARMED AWAY ###"
on_triggered:
then:
- logger.log: "### TRIGGERED ###"
on_cleared:
then:
- logger.log: "### CLEARED ###"

View File

@ -0,0 +1,64 @@
binary_sensor:
- platform: gpio
id: bin1
pin: 1
alarm_control_panel:
- platform: template
id: alarmcontrolpanel1
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_state:
then:
- lambda: !lambda |-
ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())));
- platform: template
id: alarmcontrolpanel2
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_disarmed:
then:
- logger.log: "### DISARMED ###"
on_pending:
then:
- logger.log: "### PENDING ###"
on_arming:
then:
- logger.log: "### ARMING ###"
on_armed_home:
then:
- logger.log: "### ARMED HOME ###"
on_armed_night:
then:
- logger.log: "### ARMED NIGHT ###"
on_armed_away:
then:
- logger.log: "### ARMED AWAY ###"
on_triggered:
then:
- logger.log: "### TRIGGERED ###"
on_cleared:
then:
- logger.log: "### CLEARED ###"

View File

@ -0,0 +1,64 @@
binary_sensor:
- platform: gpio
id: bin1
pin: 1
alarm_control_panel:
- platform: template
id: alarmcontrolpanel1
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_state:
then:
- lambda: !lambda |-
ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())));
- platform: template
id: alarmcontrolpanel2
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_disarmed:
then:
- logger.log: "### DISARMED ###"
on_pending:
then:
- logger.log: "### PENDING ###"
on_arming:
then:
- logger.log: "### ARMING ###"
on_armed_home:
then:
- logger.log: "### ARMED HOME ###"
on_armed_night:
then:
- logger.log: "### ARMED NIGHT ###"
on_armed_away:
then:
- logger.log: "### ARMED AWAY ###"
on_triggered:
then:
- logger.log: "### TRIGGERED ###"
on_cleared:
then:
- logger.log: "### CLEARED ###"

View File

@ -0,0 +1,64 @@
binary_sensor:
- platform: gpio
id: bin1
pin: 1
alarm_control_panel:
- platform: template
id: alarmcontrolpanel1
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_state:
then:
- lambda: !lambda |-
ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())));
- platform: template
id: alarmcontrolpanel2
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_disarmed:
then:
- logger.log: "### DISARMED ###"
on_pending:
then:
- logger.log: "### PENDING ###"
on_arming:
then:
- logger.log: "### ARMING ###"
on_armed_home:
then:
- logger.log: "### ARMED HOME ###"
on_armed_night:
then:
- logger.log: "### ARMED NIGHT ###"
on_armed_away:
then:
- logger.log: "### ARMED AWAY ###"
on_triggered:
then:
- logger.log: "### TRIGGERED ###"
on_cleared:
then:
- logger.log: "### CLEARED ###"

View File

@ -0,0 +1,64 @@
binary_sensor:
- platform: gpio
id: bin1
pin: 1
alarm_control_panel:
- platform: template
id: alarmcontrolpanel1
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_state:
then:
- lambda: !lambda |-
ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())));
- platform: template
id: alarmcontrolpanel2
name: Alarm Panel
codes:
- "1234"
requires_code_to_arm: true
arming_home_time: 1s
arming_night_time: 1s
arming_away_time: 15s
pending_time: 15s
trigger_time: 30s
binary_sensors:
- input: bin1
bypass_armed_home: true
bypass_armed_night: true
on_disarmed:
then:
- logger.log: "### DISARMED ###"
on_pending:
then:
- logger.log: "### PENDING ###"
on_arming:
then:
- logger.log: "### ARMING ###"
on_armed_home:
then:
- logger.log: "### ARMED HOME ###"
on_armed_night:
then:
- logger.log: "### ARMED NIGHT ###"
on_armed_away:
then:
- logger.log: "### ARMED AWAY ###"
on_triggered:
then:
- logger.log: "### TRIGGERED ###"
on_cleared:
then:
- logger.log: "### CLEARED ###"

View File

@ -0,0 +1,17 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: alpha3_blec
sensor:
- platform: alpha3
ble_client_id: alpha3_blec
flow:
name: "Radiator Pump Flow"
head:
name: "Radiator Pump Head"
power:
name: "Radiator Pump Power"
speed:
name: "Radiator Pump Speed"

View File

@ -0,0 +1,17 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: alpha3_blec
sensor:
- platform: alpha3
ble_client_id: alpha3_blec
flow:
name: "Radiator Pump Flow"
head:
name: "Radiator Pump Head"
power:
name: "Radiator Pump Power"
speed:
name: "Radiator Pump Speed"

View File

@ -0,0 +1,17 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: alpha3_blec
sensor:
- platform: alpha3
ble_client_id: alpha3_blec
flow:
name: "Radiator Pump Flow"
head:
name: "Radiator Pump Head"
power:
name: "Radiator Pump Power"
speed:
name: "Radiator Pump Speed"

View File

@ -0,0 +1,17 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: alpha3_blec
sensor:
- platform: alpha3
ble_client_id: alpha3_blec
flow:
name: "Radiator Pump Flow"
head:
name: "Radiator Pump Head"
power:
name: "Radiator Pump Power"
speed:
name: "Radiator Pump Speed"

View File

@ -0,0 +1,11 @@
i2c:
- id: i2c_bme280
scl: 5
sda: 4
sensor:
- platform: am2320
temperature:
name: Temperature
humidity:
name: Humidity

View File

@ -0,0 +1,11 @@
i2c:
- id: i2c_bme280
scl: 5
sda: 4
sensor:
- platform: am2320
temperature:
name: Temperature
humidity:
name: Humidity

View File

@ -0,0 +1,11 @@
i2c:
- id: i2c_bme280
scl: 16
sda: 17
sensor:
- platform: am2320
temperature:
name: Temperature
humidity:
name: Humidity

View File

@ -0,0 +1,11 @@
i2c:
- id: i2c_bme280
scl: 16
sda: 17
sensor:
- platform: am2320
temperature:
name: Temperature
humidity:
name: Humidity

View File

@ -0,0 +1,11 @@
i2c:
- id: i2c_bme280
scl: 5
sda: 4
sensor:
- platform: am2320
temperature:
name: Temperature
humidity:
name: Humidity

View File

@ -0,0 +1,11 @@
i2c:
- id: i2c_bme280
scl: 5
sda: 4
sensor:
- platform: am2320
temperature:
name: Temperature
humidity:
name: Humidity

View File

@ -0,0 +1,19 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: am43_blec
cover:
- platform: am43
name: Test AM43 Cover
id: am43_test
ble_client_id: am43_blec
sensor:
- platform: am43
ble_client_id: am43_blec
battery_level:
name: Kitchen blinds battery
illuminance:
name: Kitchen blinds light

View File

@ -0,0 +1,19 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: am43_blec
cover:
- platform: am43
name: Test AM43 Cover
id: am43_test
ble_client_id: am43_blec
sensor:
- platform: am43
ble_client_id: am43_blec
battery_level:
name: Kitchen blinds battery
illuminance:
name: Kitchen blinds light

View File

@ -0,0 +1,19 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: am43_blec
cover:
- platform: am43
name: Test AM43 Cover
id: am43_test
ble_client_id: am43_blec
sensor:
- platform: am43
ble_client_id: am43_blec
battery_level:
name: Kitchen blinds battery
illuminance:
name: Kitchen blinds light

View File

@ -0,0 +1,19 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: am43_blec
cover:
- platform: am43
name: Test AM43 Cover
id: am43_test
ble_client_id: am43_blec
sensor:
- platform: am43
ble_client_id: am43_blec
battery_level:
name: Kitchen blinds battery
illuminance:
name: Kitchen blinds light

View File

@ -0,0 +1,28 @@
sensor:
- platform: template
id: template_sensor
name: Template Sensor
lambda: |-
if (millis() > 10000) {
return 42.0;
} else {
return 0.0;
}
update_interval: 15s
binary_sensor:
- platform: analog_threshold
name: Analog Threshold 1
sensor_id: template_sensor
threshold:
upper: 110
lower: 90
filters:
- delayed_on: 0s
- delayed_off: 10s
- platform: analog_threshold
name: Analog Threshold 2
sensor_id: template_sensor
threshold: 100
filters:
- invert:

View File

@ -0,0 +1,28 @@
sensor:
- platform: template
id: template_sensor
name: Template Sensor
lambda: |-
if (millis() > 10000) {
return 42.0;
} else {
return 0.0;
}
update_interval: 15s
binary_sensor:
- platform: analog_threshold
name: Analog Threshold 1
sensor_id: template_sensor
threshold:
upper: 110
lower: 90
filters:
- delayed_on: 0s
- delayed_off: 10s
- platform: analog_threshold
name: Analog Threshold 2
sensor_id: template_sensor
threshold: 100
filters:
- invert:

View File

@ -0,0 +1,28 @@
sensor:
- platform: template
id: template_sensor
name: Template Sensor
lambda: |-
if (millis() > 10000) {
return 42.0;
} else {
return 0.0;
}
update_interval: 15s
binary_sensor:
- platform: analog_threshold
name: Analog Threshold 1
sensor_id: template_sensor
threshold:
upper: 110
lower: 90
filters:
- delayed_on: 0s
- delayed_off: 10s
- platform: analog_threshold
name: Analog Threshold 2
sensor_id: template_sensor
threshold: 100
filters:
- invert:

View File

@ -0,0 +1,28 @@
sensor:
- platform: template
id: template_sensor
name: Template Sensor
lambda: |-
if (millis() > 10000) {
return 42.0;
} else {
return 0.0;
}
update_interval: 15s
binary_sensor:
- platform: analog_threshold
name: Analog Threshold 1
sensor_id: template_sensor
threshold:
upper: 110
lower: 90
filters:
- delayed_on: 0s
- delayed_off: 10s
- platform: analog_threshold
name: Analog Threshold 2
sensor_id: template_sensor
threshold: 100
filters:
- invert:

View File

@ -0,0 +1,28 @@
sensor:
- platform: template
id: template_sensor
name: Template Sensor
lambda: |-
if (millis() > 10000) {
return 42.0;
} else {
return 0.0;
}
update_interval: 15s
binary_sensor:
- platform: analog_threshold
name: Analog Threshold 1
sensor_id: template_sensor
threshold:
upper: 110
lower: 90
filters:
- delayed_on: 0s
- delayed_off: 10s
- platform: analog_threshold
name: Analog Threshold 2
sensor_id: template_sensor
threshold: 100
filters:
- invert:

View File

@ -0,0 +1,28 @@
sensor:
- platform: template
id: template_sensor
name: Template Sensor
lambda: |-
if (millis() > 10000) {
return 42.0;
} else {
return 0.0;
}
update_interval: 15s
binary_sensor:
- platform: analog_threshold
name: Analog Threshold 1
sensor_id: template_sensor
threshold:
upper: 110
lower: 90
filters:
- delayed_on: 0s
- delayed_off: 10s
- platform: analog_threshold
name: Analog Threshold 2
sensor_id: template_sensor
threshold: 100
filters:
- invert:

View File

@ -0,0 +1,23 @@
spi:
- id: spi_main_lcd
clk_pin: 6
mosi_pin: 7
miso_pin: 5
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 8
dc_pin: 9
reset_pin: 10
# Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined.
# image:
animation:
- id: rgb565_animation
file: ../../pnglogo.png
type: RGB565
use_transparency: no

View File

@ -0,0 +1,23 @@
spi:
- id: spi_main_lcd
clk_pin: 6
mosi_pin: 7
miso_pin: 5
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 8
dc_pin: 9
reset_pin: 10
# Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined.
# image:
animation:
- id: rgb565_animation
file: ../../pnglogo.png
type: RGB565
use_transparency: no

View File

@ -0,0 +1,23 @@
spi:
- id: spi_main_lcd
clk_pin: 16
mosi_pin: 17
miso_pin: 15
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 12
dc_pin: 13
reset_pin: 21
# Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined.
# image:
animation:
- id: rgb565_animation
file: ../../pnglogo.png
type: RGB565
use_transparency: no

View File

@ -0,0 +1,23 @@
spi:
- id: spi_main_lcd
clk_pin: 16
mosi_pin: 17
miso_pin: 15
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 12
dc_pin: 13
reset_pin: 21
# Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined.
# image:
animation:
- id: rgb565_animation
file: ../../pnglogo.png
type: RGB565
use_transparency: no

View File

@ -0,0 +1,23 @@
spi:
- id: spi_main_lcd
clk_pin: 14
mosi_pin: 13
miso_pin: 12
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 5
dc_pin: 15
reset_pin: 16
# Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined.
# image:
animation:
- id: rgb565_animation
file: ../../pnglogo.png
type: RGB565
use_transparency: no

View File

@ -0,0 +1,23 @@
spi:
- id: spi_main_lcd
clk_pin: 2
mosi_pin: 3
miso_pin: 4
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 20
dc_pin: 21
reset_pin: 22
# Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined.
# image:
animation:
- id: rgb565_animation
file: ../../pnglogo.png
type: RGB565
use_transparency: no

View File

@ -0,0 +1,11 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: anova_blec
climate:
- platform: anova
name: Anova cooker
ble_client_id: anova_blec
unit_of_measurement: c

View File

@ -0,0 +1,11 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: anova_blec
climate:
- platform: anova
name: Anova cooker
ble_client_id: anova_blec
unit_of_measurement: c

View File

@ -0,0 +1,11 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: anova_blec
climate:
- platform: anova
name: Anova cooker
ble_client_id: anova_blec
unit_of_measurement: c

View File

@ -0,0 +1,11 @@
esp32_ble_tracker:
ble_client:
- mac_address: 01:02:03:04:05:06
id: anova_blec
climate:
- platform: anova
name: Anova cooker
ble_client_id: anova_blec
unit_of_measurement: c

View File

@ -0,0 +1,48 @@
i2c:
- id: i2c_bme280
scl: 5
sda: 4
apds9960:
address: 0x20
update_interval: 60s
binary_sensor:
- platform: apds9960
id: apds9960_binary_sensor
direction: up
name: APDS9960 Up
device_class: motion
filters:
- invert
- delayed_on: 20ms
- delayed_off: 20ms
- lambda: "return false;"
on_state:
- logger.log: New state
- platform: apds9960
direction: down
name: APDS9960 Down
- platform: apds9960
direction: left
name: APDS9960 Left
- platform: apds9960
direction: right
name: APDS9960 Right
sensor:
- platform: apds9960
type: proximity
name: APDS9960 Proximity
- platform: apds9960
type: clear
name: APDS9960 Clear
- platform: apds9960
type: red
name: APDS9960 Red
- platform: apds9960
type: green
name: APDS9960 Green
- platform: apds9960
type: blue
name: APDS9960 Blue

View File

@ -0,0 +1,48 @@
i2c:
- id: i2c_bme280
scl: 5
sda: 4
apds9960:
address: 0x20
update_interval: 60s
binary_sensor:
- platform: apds9960
id: apds9960_binary_sensor
direction: up
name: APDS9960 Up
device_class: motion
filters:
- invert
- delayed_on: 20ms
- delayed_off: 20ms
- lambda: "return false;"
on_state:
- logger.log: New state
- platform: apds9960
direction: down
name: APDS9960 Down
- platform: apds9960
direction: left
name: APDS9960 Left
- platform: apds9960
direction: right
name: APDS9960 Right
sensor:
- platform: apds9960
type: proximity
name: APDS9960 Proximity
- platform: apds9960
type: clear
name: APDS9960 Clear
- platform: apds9960
type: red
name: APDS9960 Red
- platform: apds9960
type: green
name: APDS9960 Green
- platform: apds9960
type: blue
name: APDS9960 Blue

View File

@ -0,0 +1,48 @@
i2c:
- id: i2c_bme280
scl: 16
sda: 17
apds9960:
address: 0x20
update_interval: 60s
binary_sensor:
- platform: apds9960
id: apds9960_binary_sensor
direction: up
name: APDS9960 Up
device_class: motion
filters:
- invert
- delayed_on: 20ms
- delayed_off: 20ms
- lambda: "return false;"
on_state:
- logger.log: New state
- platform: apds9960
direction: down
name: APDS9960 Down
- platform: apds9960
direction: left
name: APDS9960 Left
- platform: apds9960
direction: right
name: APDS9960 Right
sensor:
- platform: apds9960
type: proximity
name: APDS9960 Proximity
- platform: apds9960
type: clear
name: APDS9960 Clear
- platform: apds9960
type: red
name: APDS9960 Red
- platform: apds9960
type: green
name: APDS9960 Green
- platform: apds9960
type: blue
name: APDS9960 Blue

View File

@ -0,0 +1,48 @@
i2c:
- id: i2c_bme280
scl: 16
sda: 17
apds9960:
address: 0x20
update_interval: 60s
binary_sensor:
- platform: apds9960
id: apds9960_binary_sensor
direction: up
name: APDS9960 Up
device_class: motion
filters:
- invert
- delayed_on: 20ms
- delayed_off: 20ms
- lambda: "return false;"
on_state:
- logger.log: New state
- platform: apds9960
direction: down
name: APDS9960 Down
- platform: apds9960
direction: left
name: APDS9960 Left
- platform: apds9960
direction: right
name: APDS9960 Right
sensor:
- platform: apds9960
type: proximity
name: APDS9960 Proximity
- platform: apds9960
type: clear
name: APDS9960 Clear
- platform: apds9960
type: red
name: APDS9960 Red
- platform: apds9960
type: green
name: APDS9960 Green
- platform: apds9960
type: blue
name: APDS9960 Blue

View File

@ -0,0 +1,48 @@
i2c:
- id: i2c_bme280
scl: 5
sda: 4
apds9960:
address: 0x20
update_interval: 60s
binary_sensor:
- platform: apds9960
id: apds9960_binary_sensor
direction: up
name: APDS9960 Up
device_class: motion
filters:
- invert
- delayed_on: 20ms
- delayed_off: 20ms
- lambda: "return false;"
on_state:
- logger.log: New state
- platform: apds9960
direction: down
name: APDS9960 Down
- platform: apds9960
direction: left
name: APDS9960 Left
- platform: apds9960
direction: right
name: APDS9960 Right
sensor:
- platform: apds9960
type: proximity
name: APDS9960 Proximity
- platform: apds9960
type: clear
name: APDS9960 Clear
- platform: apds9960
type: red
name: APDS9960 Red
- platform: apds9960
type: green
name: APDS9960 Green
- platform: apds9960
type: blue
name: APDS9960 Blue

View File

@ -0,0 +1,48 @@
i2c:
- id: i2c_bme280
scl: 5
sda: 4
apds9960:
address: 0x20
update_interval: 60s
binary_sensor:
- platform: apds9960
id: apds9960_binary_sensor
direction: up
name: APDS9960 Up
device_class: motion
filters:
- invert
- delayed_on: 20ms
- delayed_off: 20ms
- lambda: "return false;"
on_state:
- logger.log: New state
- platform: apds9960
direction: down
name: APDS9960 Down
- platform: apds9960
direction: left
name: APDS9960 Left
- platform: apds9960
direction: right
name: APDS9960 Right
sensor:
- platform: apds9960
type: proximity
name: APDS9960 Proximity
- platform: apds9960
type: clear
name: APDS9960 Clear
- platform: apds9960
type: red
name: APDS9960 Red
- platform: apds9960
type: green
name: APDS9960 Green
- platform: apds9960
type: blue
name: APDS9960 Blue

View File

@ -0,0 +1,50 @@
wifi:
ssid: MySSID
password: password1
api:
port: 8000
password: pwd
reboot_timeout: 0min
encryption:
key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU=
services:
- service: hello_world
variables:
name: string
then:
- logger.log:
format: Hello World %s!
args:
- name.c_str()
- service: empty_service
then:
- logger.log: Service Called
- service: all_types
variables:
bool_: bool
int_: int
float_: float
string_: string
then:
- logger.log: Something happened
- service: array_types
variables:
bool_arr: bool[]
int_arr: int[]
float_arr: float[]
string_arr: string[]
then:
- logger.log:
# yamllint disable rule:line-length
format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)"
# yamllint enable rule:line-length
args:
- YESNO(bool_arr[0])
- bool_arr.size()
- int_arr[0]
- int_arr.size()
- float_arr[0]
- float_arr.size()
- string_arr[0].c_str()
- string_arr.size()

View File

@ -0,0 +1,50 @@
wifi:
ssid: MySSID
password: password1
api:
port: 8000
password: pwd
reboot_timeout: 0min
encryption:
key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU=
services:
- service: hello_world
variables:
name: string
then:
- logger.log:
format: Hello World %s!
args:
- name.c_str()
- service: empty_service
then:
- logger.log: Service Called
- service: all_types
variables:
bool_: bool
int_: int
float_: float
string_: string
then:
- logger.log: Something happened
- service: array_types
variables:
bool_arr: bool[]
int_arr: int[]
float_arr: float[]
string_arr: string[]
then:
- logger.log:
# yamllint disable rule:line-length
format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)"
# yamllint enable rule:line-length
args:
- YESNO(bool_arr[0])
- bool_arr.size()
- int_arr[0]
- int_arr.size()
- float_arr[0]
- float_arr.size()
- string_arr[0].c_str()
- string_arr.size()

View File

@ -0,0 +1,50 @@
wifi:
ssid: MySSID
password: password1
api:
port: 8000
password: pwd
reboot_timeout: 0min
encryption:
key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU=
services:
- service: hello_world
variables:
name: string
then:
- logger.log:
format: Hello World %s!
args:
- name.c_str()
- service: empty_service
then:
- logger.log: Service Called
- service: all_types
variables:
bool_: bool
int_: int
float_: float
string_: string
then:
- logger.log: Something happened
- service: array_types
variables:
bool_arr: bool[]
int_arr: int[]
float_arr: float[]
string_arr: string[]
then:
- logger.log:
# yamllint disable rule:line-length
format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)"
# yamllint enable rule:line-length
args:
- YESNO(bool_arr[0])
- bool_arr.size()
- int_arr[0]
- int_arr.size()
- float_arr[0]
- float_arr.size()
- string_arr[0].c_str()
- string_arr.size()

View File

@ -0,0 +1,50 @@
wifi:
ssid: MySSID
password: password1
api:
port: 8000
password: pwd
reboot_timeout: 0min
encryption:
key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU=
services:
- service: hello_world
variables:
name: string
then:
- logger.log:
format: Hello World %s!
args:
- name.c_str()
- service: empty_service
then:
- logger.log: Service Called
- service: all_types
variables:
bool_: bool
int_: int
float_: float
string_: string
then:
- logger.log: Something happened
- service: array_types
variables:
bool_arr: bool[]
int_arr: int[]
float_arr: float[]
string_arr: string[]
then:
- logger.log:
# yamllint disable rule:line-length
format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)"
# yamllint enable rule:line-length
args:
- YESNO(bool_arr[0])
- bool_arr.size()
- int_arr[0]
- int_arr.size()
- float_arr[0]
- float_arr.size()
- string_arr[0].c_str()
- string_arr.size()

View File

@ -0,0 +1,50 @@
wifi:
ssid: MySSID
password: password1
api:
port: 8000
password: pwd
reboot_timeout: 0min
encryption:
key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU=
services:
- service: hello_world
variables:
name: string
then:
- logger.log:
format: Hello World %s!
args:
- name.c_str()
- service: empty_service
then:
- logger.log: Service Called
- service: all_types
variables:
bool_: bool
int_: int
float_: float
string_: string
then:
- logger.log: Something happened
- service: array_types
variables:
bool_arr: bool[]
int_arr: int[]
float_arr: float[]
string_arr: string[]
then:
- logger.log:
# yamllint disable rule:line-length
format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)"
# yamllint enable rule:line-length
args:
- YESNO(bool_arr[0])
- bool_arr.size()
- int_arr[0]
- int_arr.size()
- float_arr[0]
- float_arr.size()
- string_arr[0].c_str()
- string_arr.size()

View File

@ -0,0 +1,50 @@
wifi:
ssid: MySSID
password: password1
api:
port: 8000
password: pwd
reboot_timeout: 0min
encryption:
key: bOFFzzvfpg5DB94DuBGLXD/hMnhpDKgP9UQyBulwWVU=
services:
- service: hello_world
variables:
name: string
then:
- logger.log:
format: Hello World %s!
args:
- name.c_str()
- service: empty_service
then:
- logger.log: Service Called
- service: all_types
variables:
bool_: bool
int_: int
float_: float
string_: string
then:
- logger.log: Something happened
- service: array_types
variables:
bool_arr: bool[]
int_arr: int[]
float_arr: float[]
string_arr: string[]
then:
- logger.log:
# yamllint disable rule:line-length
format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)"
# yamllint enable rule:line-length
args:
- YESNO(bool_arr[0])
- bool_arr.size()
- int_arr[0]
- int_arr.size()
- float_arr[0]
- float_arr.size()
- string_arr[0].c_str()
- string_arr.size()

View File

@ -0,0 +1,18 @@
i2c:
- id: i2c_as3935
scl: 5
sda: 4
as3935_i2c:
irq_pin: 6
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,18 @@
i2c:
- id: i2c_as3935
scl: 5
sda: 4
as3935_i2c:
irq_pin: 6
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,18 @@
i2c:
- id: i2c_as3935
scl: 16
sda: 17
as3935_i2c:
irq_pin: 12
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,18 @@
i2c:
- id: i2c_as3935
scl: 16
sda: 17
as3935_i2c:
irq_pin: 12
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,18 @@
i2c:
- id: i2c_as3935
scl: 5
sda: 4
as3935_i2c:
irq_pin: 15
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,18 @@
i2c:
- id: i2c_as3935
scl: 5
sda: 4
as3935_i2c:
irq_pin: 6
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,20 @@
spi:
- id: spi_as3935
clk_pin: 6
mosi_pin: 7
miso_pin: 5
as3935_spi:
cs_pin: 2
irq_pin: 3
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,20 @@
spi:
- id: spi_as3935
clk_pin: 6
mosi_pin: 7
miso_pin: 5
as3935_spi:
cs_pin: 2
irq_pin: 3
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,20 @@
spi:
- id: spi_as3935
clk_pin: 16
mosi_pin: 17
miso_pin: 15
as3935_spi:
cs_pin: 12
irq_pin: 13
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,20 @@
spi:
- id: spi_as3935
clk_pin: 16
mosi_pin: 17
miso_pin: 15
as3935_spi:
cs_pin: 12
irq_pin: 13
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,20 @@
spi:
- id: spi_as3935
clk_pin: 14
mosi_pin: 13
miso_pin: 12
as3935_spi:
cs_pin: 15
irq_pin: 16
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,20 @@
spi:
- id: spi_as3935
clk_pin: 2
mosi_pin: 3
miso_pin: 4
as3935_spi:
cs_pin: 6
irq_pin: 7
binary_sensor:
- platform: as3935
name: Storm Alert
sensor:
- platform: as3935
lightning_energy:
name: Lightning Energy
distance:
name: Distance Storm

View File

@ -0,0 +1,27 @@
i2c:
- id: i2c_as5600
scl: 5
sda: 4
as5600:
dir_pin: 6
direction: clockwise
start_position: 90deg
range: 180deg
watchdog: true
power_mode: low1
hysteresis: lsb1
slow_filter: 8x
fast_filter: lsb6
sensor:
- platform: as5600
name: AS5600 Position
raw_position:
name: AS5600 Raw Position
gain:
name: AS5600 Gain
magnitude:
name: AS5600 Magnitude
status:
name: AS5600 Status

View File

@ -0,0 +1,27 @@
i2c:
- id: i2c_as5600
scl: 5
sda: 4
as5600:
dir_pin: 6
direction: clockwise
start_position: 90deg
range: 180deg
watchdog: true
power_mode: low1
hysteresis: lsb1
slow_filter: 8x
fast_filter: lsb6
sensor:
- platform: as5600
name: AS5600 Position
raw_position:
name: AS5600 Raw Position
gain:
name: AS5600 Gain
magnitude:
name: AS5600 Magnitude
status:
name: AS5600 Status

View File

@ -0,0 +1,27 @@
i2c:
- id: i2c_as5600
scl: 16
sda: 17
as5600:
dir_pin: 12
direction: clockwise
start_position: 90deg
range: 180deg
watchdog: true
power_mode: low1
hysteresis: lsb1
slow_filter: 8x
fast_filter: lsb6
sensor:
- platform: as5600
name: AS5600 Position
raw_position:
name: AS5600 Raw Position
gain:
name: AS5600 Gain
magnitude:
name: AS5600 Magnitude
status:
name: AS5600 Status

View File

@ -0,0 +1,27 @@
i2c:
- id: i2c_as5600
scl: 16
sda: 17
as5600:
dir_pin: 12
direction: clockwise
start_position: 90deg
range: 180deg
watchdog: true
power_mode: low1
hysteresis: lsb1
slow_filter: 8x
fast_filter: lsb6
sensor:
- platform: as5600
name: AS5600 Position
raw_position:
name: AS5600 Raw Position
gain:
name: AS5600 Gain
magnitude:
name: AS5600 Magnitude
status:
name: AS5600 Status

View File

@ -0,0 +1,27 @@
i2c:
- id: i2c_as5600
scl: 5
sda: 4
as5600:
dir_pin: 15
direction: clockwise
start_position: 90deg
range: 180deg
watchdog: true
power_mode: low1
hysteresis: lsb1
slow_filter: 8x
fast_filter: lsb6
sensor:
- platform: as5600
name: AS5600 Position
raw_position:
name: AS5600 Raw Position
gain:
name: AS5600 Gain
magnitude:
name: AS5600 Magnitude
status:
name: AS5600 Status

View File

@ -0,0 +1,27 @@
i2c:
- id: i2c_as5600
scl: 5
sda: 4
as5600:
dir_pin: 6
direction: clockwise
start_position: 90deg
range: 180deg
watchdog: true
power_mode: low1
hysteresis: lsb1
slow_filter: 8x
fast_filter: lsb6
sensor:
- platform: as5600
name: AS5600 Position
raw_position:
name: AS5600 Raw Position
gain:
name: AS5600 Gain
magnitude:
name: AS5600 Magnitude
status:
name: AS5600 Status

View File

@ -0,0 +1,31 @@
i2c:
- id: i2c_as5600
scl: 5
sda: 4
sensor:
- platform: as7341
update_interval: 15s
gain: X8
atime: 120
astep: 99
f1:
name: F1
f2:
name: F2
f3:
name: F3
f4:
name: F4
f5:
name: F5
f6:
name: F6
f7:
name: F7
f8:
name: F8
clear:
name: Clear
nir:
name: NIR

View File

@ -0,0 +1,31 @@
i2c:
- id: i2c_as5600
scl: 5
sda: 4
sensor:
- platform: as7341
update_interval: 15s
gain: X8
atime: 120
astep: 99
f1:
name: F1
f2:
name: F2
f3:
name: F3
f4:
name: F4
f5:
name: F5
f6:
name: F6
f7:
name: F7
f8:
name: F8
clear:
name: Clear
nir:
name: NIR

View File

@ -0,0 +1,31 @@
i2c:
- id: i2c_as5600
scl: 16
sda: 17
sensor:
- platform: as7341
update_interval: 15s
gain: X8
atime: 120
astep: 99
f1:
name: F1
f2:
name: F2
f3:
name: F3
f4:
name: F4
f5:
name: F5
f6:
name: F6
f7:
name: F7
f8:
name: F8
clear:
name: Clear
nir:
name: NIR

View File

@ -0,0 +1,31 @@
i2c:
- id: i2c_as5600
scl: 16
sda: 17
sensor:
- platform: as7341
update_interval: 15s
gain: X8
atime: 120
astep: 99
f1:
name: F1
f2:
name: F2
f3:
name: F3
f4:
name: F4
f5:
name: F5
f6:
name: F6
f7:
name: F7
f8:
name: F8
clear:
name: Clear
nir:
name: NIR

View File

@ -0,0 +1,31 @@
i2c:
- id: i2c_as5600
scl: 5
sda: 4
sensor:
- platform: as7341
update_interval: 15s
gain: X8
atime: 120
astep: 99
f1:
name: F1
f2:
name: F2
f3:
name: F3
f4:
name: F4
f5:
name: F5
f6:
name: F6
f7:
name: F7
f8:
name: F8
clear:
name: Clear
nir:
name: NIR

View File

@ -0,0 +1,31 @@
i2c:
- id: i2c_as5600
scl: 5
sda: 4
sensor:
- platform: as7341
update_interval: 15s
gain: X8
atime: 120
astep: 99
f1:
name: F1
f2:
name: F2
f3:
name: F3
f4:
name: F4
f5:
name: F5
f6:
name: F6
f7:
name: F7
f8:
name: F8
clear:
name: Clear
nir:
name: NIR

Some files were not shown because too many files have changed in this diff Show More