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