ESPHome  2024.11.0
adalight_light_effect.cpp
Go to the documentation of this file.
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace adalight {
6 
7 static const char *const TAG = "adalight_light_effect";
8 
9 static const uint32_t ADALIGHT_ACK_INTERVAL = 1000;
10 static const uint32_t ADALIGHT_RECEIVE_TIMEOUT = 1000;
11 
12 AdalightLightEffect::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 
28 unsigned 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 
50 void AdalightLightEffect::apply(light::AddressableLight &it, const Color &current_color) {
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);
62  blank_all_leds_(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);
69  blank_all_leds_(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
void reset_frame_(light::AddressableLight &it)
void write_str(const char *str)
Definition: uart.h:27
const char * name
Definition: stm32flash.h:78
Frame parse_frame_(light::AddressableLight &it)
uint8_t checksum
Definition: bl0906.h:210
void blank_all_leds_(light::AddressableLight &it)
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
bool read_byte(uint8_t *data)
Definition: uart.h:29
virtual int32_t size() const =0
unsigned int get_frame_size_(int led_count) const
static const Color BLACK
Definition: color.h:168
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7