This commit is contained in:
kislovdm
2025-07-24 20:16:10 +03:00
parent fa8fa935df
commit b4c02dd456
7 changed files with 235 additions and 36 deletions
@@ -0,0 +1,6 @@
# Добавляем файл генерации рецептов
src_files(
saeco_series_6000.cpp
recipe.cpp
crc.cpp
)
+43
View File
@@ -0,0 +1,43 @@
#include "saeco_series_6000.h"
#include <vector>
namespace esphome {
namespace saeco_series_6000 {
uint32_t SaecoSeries6000::calc_crc(const std::vector<uint8_t>& data, size_t start, size_t end) {
uint32_t crc = 0xFFFFFFFF;
const uint32_t POLY = 0x04C11DB7;
if (start >= end) return 0;
// start
uint8_t val = data[start];
((uint8_t*)(&crc))[3] ^= BitReverse[val];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x80000000) {
crc = (crc << 1) ^ POLY;
} else {
crc <<= 1;
}
}
// остальные байты
for (size_t i = start + 1; i < end; i++) {
uint8_t v = data[i];
((uint8_t*)(&crc))[3] ^= BitReverse[v];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x80000000) {
crc = (crc << 1) ^ POLY;
} else {
crc <<= 1;
}
}
}
uint32_t t32 = 0;
((uint8_t*)(&t32))[0] = BitReverse[((uint8_t*)(&crc))[3]];
((uint8_t*)(&t32))[1] = BitReverse[((uint8_t*)(&crc))[2]];
((uint8_t*)(&t32))[2] = BitReverse[((uint8_t*)(&crc))[1]];
((uint8_t*)(&t32))[3] = BitReverse[((uint8_t*)(&crc))[0]];
crc = t32 ^ 0xFFFFFFFF;
return crc;
}
} // namespace saeco_series_6000
} // namespace esphome
+59
View File
@@ -0,0 +1,59 @@
#include "saeco_series_6000.h"
#include <vector>
namespace esphome {
namespace saeco_series_6000 {
std::vector<uint8_t> SaecoSeries6000::build_coffee_recipe(uint8_t type, uint8_t bean, uint8_t cups, uint16_t vol, uint16_t milk) {
static const uint8_t CoffeePattern[7][4] = {
{0,1,1,2}, // Espresso
{1,2,3,2}, // Americano
{2,2,1,2}, // Cappuccino
{3,2,2,2}, // Latte
{4,0,0,1}, // Coffee with milk
{5,1,0,1}, // Milk foam
{6,0,0,1} // Hot water
};
uint8_t rec[10] = {0};
if (type >= 7) type = 0;
rec[0] = CoffeePattern[type][0];
if (rec[0] == 5 || rec[0] == 4) {
rec[1] = 3; // всегда молотый для молока и milk foam
} else {
rec[1] = bean;
}
if (cups > CoffeePattern[type][3]) {
rec[2] = CoffeePattern[type][3];
} else {
rec[2] = cups;
}
rec[3] = CoffeePattern[type][1];
rec[4] = CoffeePattern[type][2];
if (rec[0] == 1) { // Americano
rec[6] = 40;
rec[7] = 0;
rec[8] = (uint8_t)vol;
rec[9] = vol / 0x100;
rec[5] = 0;
} else {
rec[6] = (uint8_t)vol;
rec[7] = vol / 0x100;
if (rec[0] == 0 || rec[0] == 1 || rec[0] == 4 || rec[0] == 5) {
if (rec[0] == 5) {
rec[5] = 2;
} else {
rec[5] = 0;
}
rec[8] = 0;
rec[9] = 0;
} else {
rec[5] = 2;
rec[8] = (uint8_t)milk;
rec[9] = milk / 0x100;
}
}
return std::vector<uint8_t>(rec, rec + 10);
}
} // namespace saeco_series_6000
} // namespace esphome
@@ -24,6 +24,7 @@ void SaecoSeries6000::loop() {
uart_display_->write_byte(byte); // Mirror byte immediately
process_mainboard_byte(byte); // Process the "sniffed" byte
}
// Контроль активности UART (выключение через 15 сек)
static uint32_t last_check = 0;
uint32_t now = millis();
@@ -232,41 +233,6 @@ const uint8_t SaecoSeries6000::BitReverse[256] = {
0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
};
uint32_t SaecoSeries6000::calc_crc(const std::vector<uint8_t>& data, size_t start, size_t end) {
uint32_t crc = 0xFFFFFFFF;
const uint32_t POLY = 0x04C11DB7;
if (start >= end) return 0;
// start
uint8_t val = data[start];
((uint8_t*)(&crc))[3] ^= BitReverse[val];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x80000000) {
crc = (crc << 1) ^ POLY;
} else {
crc <<= 1;
}
}
// остальные байты
for (size_t i = start + 1; i < end; i++) {
uint8_t v = data[i];
((uint8_t*)(&crc))[3] ^= BitReverse[v];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x80000000) {
crc = (crc << 1) ^ POLY;
} else {
crc <<= 1;
}
}
}
uint32_t t32 = 0;
((uint8_t*)(&t32))[0] = BitReverse[((uint8_t*)(&crc))[3]];
((uint8_t*)(&t32))[1] = BitReverse[((uint8_t*)(&crc))[2]];
((uint8_t*)(&t32))[2] = BitReverse[((uint8_t*)(&crc))[1]];
((uint8_t*)(&t32))[3] = BitReverse[((uint8_t*)(&crc))[0]];
crc = t32 ^ 0xFFFFFFFF;
return crc;
}
std::vector<uint8_t> SaecoSeries6000::parse_hex_string_to_bytes(const std::string& hex_string) {
std::vector<uint8_t> pkt;
size_t pos = 0;
@@ -339,5 +305,26 @@ void SaecoSeries6000::send_packets_to_mainboard(const std::vector<std::vector<ui
// Реализация SendPacketsAction полностью в header (saeco_series_6000.h)
void SaecoSeries6000::coffee_build(uint8_t type, uint8_t bean, uint8_t cups, uint16_t vol, uint16_t milk) {
// Формируем пакет для отправки (AA AA AA 90 ... CRC CRC CRC CRC 55)
std::vector<uint8_t> pkt = {0xAA, 0xAA, 0xAA, 0x90};
std::vector<uint8_t> rec = build_coffee_recipe(type, bean, cups, vol, milk);
pkt.insert(pkt.end(), rec.begin(), rec.end());
// Добавляем 4 байта CRC (заполним позже) и 0x55
pkt.resize(pkt.size() + 4 + 1, 0);
pkt[pkt.size() - 1] = 0x55;
// Пересчёт CRC
size_t preamble = 3;
size_t crc_start = preamble;
size_t crc_end = pkt.size() - 5;
uint32_t crc = calc_crc(pkt, crc_start, crc_end);
pkt[pkt.size()-2] = (crc >> 24) & 0xFF;
pkt[pkt.size()-3] = (crc >> 16) & 0xFF;
pkt[pkt.size()-4] = (crc >> 8) & 0xFF;
pkt[pkt.size()-5] = crc & 0xFF;
// Отправляем пакет
send_packets_to_mainboard(std::vector<std::vector<uint8_t>>{pkt});
}
} // namespace saeco_series_6000
} // namespace esphome
@@ -26,6 +26,28 @@ class SaecoSeries6000 : public Component {
void send_packets_to_mainboard(const std::vector<std::string>& hex_packets, uint32_t delay_ms = 10);
void send_packets_to_mainboard(const std::string& hex_packet, uint32_t delay_ms = 10);
// Типы напитков
enum CoffeeType {
ESPRESSO = 0,
AMERICANO = 1,
CAPPUCCINO = 2,
LATTE = 3,
COFFEE_WITH_MILK = 4,
MILK_FOAM = 5,
HOT_WATER = 6
};
// Крепость/помол
enum CoffeeStrength {
MILD = 0,
NORMAL = 1,
STRONG = 2,
GROUND = 3
};
// Построение и отправка пакета приготовления кофе
void coffee_build(uint8_t type, uint8_t bean, uint8_t cups, uint16_t vol, uint16_t milk);
// Генерация рецепта (только формирование данных)
static std::vector<uint8_t> build_coffee_recipe(uint8_t type, uint8_t bean, uint8_t cups, uint16_t vol, uint16_t milk);
protected:
uart::UARTComponent *uart_display_;
uart::UARTComponent *uart_mainboard_;
@@ -57,7 +79,8 @@ class SaecoSeries6000 : public Component {
void parse_b5_packet(const uint8_t* buffer, uint16_t size);
void pub_status(uint8_t status);
static const uint8_t BitReverse[256];
uint32_t calc_crc(const std::vector<uint8_t>& data, size_t start, size_t end);
// CRC-32 для пакетов кофемашины
static uint32_t calc_crc(const std::vector<uint8_t>& data, size_t start, size_t end);
std::vector<uint8_t> parse_hex_string_to_bytes(const std::string& hex_string);
};