ESPHome 2025.5.0
Loading...
Searching...
No Matches
adalight_light_effect.cpp
Go to the documentation of this file.
2#include "esphome/core/log.h"
3
4namespace esphome {
5namespace adalight {
6
7static const char *const TAG = "adalight_light_effect";
8
9static const uint32_t ADALIGHT_ACK_INTERVAL = 1000;
10static const uint32_t ADALIGHT_RECEIVE_TIMEOUT = 1000;
11
12AdalightLightEffect::AdalightLightEffect(const std::string &name) : AddressableLightEffect(name) {}
13
15 AddressableLightEffect::start();
16
17 last_ack_ = 0;
18 last_byte_ = 0;
19 last_reset_ = 0;
20}
21
23 frame_.resize(0);
24
25 AddressableLightEffect::stop();
26}
27
28unsigned int AdalightLightEffect::get_frame_size_(int led_count) const {
29 // 3 bytes: Ada
30 // 2 bytes: LED count
31 // 1 byte: checksum
32 // 3 bytes per LED
33 return 3 + 2 + 1 + led_count * 3;
34}
35
37 int buffer_capacity = get_frame_size_(it.size());
38
39 frame_.clear();
40 frame_.reserve(buffer_capacity);
41}
42
44 for (int led = it.size(); led-- > 0;) {
45 it[led].set(Color::BLACK);
46 }
47 it.schedule_show();
48}
49
51 const uint32_t now = millis();
52
53 if (now - this->last_ack_ >= ADALIGHT_ACK_INTERVAL) {
54 ESP_LOGV(TAG, "Sending ACK");
55 this->write_str("Ada\n");
56 this->last_ack_ = now;
57 }
58
59 if (!this->last_reset_) {
60 ESP_LOGW(TAG, "Frame: Reset.");
61 reset_frame_(it);
63 this->last_reset_ = now;
64 }
65
66 if (!this->frame_.empty() && now - this->last_byte_ >= ADALIGHT_RECEIVE_TIMEOUT) {
67 ESP_LOGW(TAG, "Frame: Receive timeout (size=%zu).", this->frame_.size());
68 reset_frame_(it);
70 }
71
72 if (this->available() > 0) {
73 ESP_LOGV(TAG, "Frame: Available (size=%d).", this->available());
74 }
75
76 while (this->available() != 0) {
77 uint8_t data;
78 if (!this->read_byte(&data))
79 break;
80 this->frame_.push_back(data);
81 this->last_byte_ = now;
82
83 switch (this->parse_frame_(it)) {
84 case INVALID:
85 ESP_LOGD(TAG, "Frame: Invalid (size=%zu, first=%d).", this->frame_.size(), this->frame_[0]);
86 reset_frame_(it);
87 break;
88
89 case PARTIAL:
90 break;
91
92 case CONSUMED:
93 ESP_LOGV(TAG, "Frame: Consumed (size=%zu).", this->frame_.size());
94 reset_frame_(it);
95 break;
96 }
97 }
98}
99
101 if (frame_.empty())
102 return INVALID;
103
104 // Check header: `Ada`
105 if (frame_[0] != 'A')
106 return INVALID;
107 if (frame_.size() > 1 && frame_[1] != 'd')
108 return INVALID;
109 if (frame_.size() > 2 && frame_[2] != 'a')
110 return INVALID;
111
112 // 3 bytes: Count Hi, Count Lo, Checksum
113 if (frame_.size() < 6)
114 return PARTIAL;
115
116 // Check checksum
117 uint16_t checksum = frame_[3] ^ frame_[4] ^ 0x55;
118 if (checksum != frame_[5])
119 return INVALID;
120
121 // Check if we received the full frame
122 uint16_t led_count = (frame_[3] << 8) + frame_[4] + 1;
123 auto buffer_size = get_frame_size_(led_count);
124 if (frame_.size() < buffer_size)
125 return PARTIAL;
126
127 // Apply lights
128 auto accepted_led_count = std::min<int>(led_count, it.size());
129 uint8_t *led_data = &frame_[6];
130
131 for (int led = 0; led < accepted_led_count; led++, led_data += 3) {
132 auto white = std::min(std::min(led_data[0], led_data[1]), led_data[2]);
133
134 it[led].set(Color(led_data[0], led_data[1], led_data[2], white));
135 }
136
137 it.schedule_show();
138 return CONSUMED;
139}
140
141} // namespace adalight
142} // namespace esphome
uint8_t checksum
Definition bl0906.h:3
unsigned int get_frame_size_(int led_count) const
void blank_all_leds_(light::AddressableLight &it)
Frame parse_frame_(light::AddressableLight &it)
void reset_frame_(light::AddressableLight &it)
virtual int32_t size() const =0
void write_str(const char *str)
Definition uart.h:27
bool read_byte(uint8_t *data)
Definition uart.h:29
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:27
static const Color BLACK
Definition color.h:168