added HA integration (not discovered)

This commit is contained in:
2022-09-16 12:13:13 +02:00
parent 938c6f7481
commit 034eb4c393
10 changed files with 261 additions and 244 deletions

View File

@@ -23,25 +23,19 @@ lib_deps =
askuric/Simple FOC @ 2.2.0 askuric/Simple FOC @ 2.2.0
infineon/TLV493D-Magnetic-Sensor @ 1.0.3 infineon/TLV493D-Magnetic-Sensor @ 1.0.3
bxparks/AceButton @ 1.9.1 bxparks/AceButton @ 1.9.1
build_flags = build_flags =
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
[env:view] [env:view]
extends = base_config extends = base_config
; platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
; platform_packages =
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
board = esp32doit-devkit-v1 board = esp32doit-devkit-v1
lib_deps = lib_deps =
; askuric/Simple FOC @ 2.2.1
; bxparks/AceButton @ 1.9.1
${base_config.lib_deps} ${base_config.lib_deps}
bodmer/TFT_eSPI@2.4.25 bodmer/TFT_eSPI@2.4.25
fastled/FastLED @ 3.5.0 fastled/FastLED @ 3.5.0
bogde/HX711 @ 0.7.5 bogde/HX711 @ 0.7.5
adafruit/Adafruit VEML7700 Library @ 1.1.1 adafruit/Adafruit VEML7700 Library @ 1.1.1
dawidchyrzynski/home-assistant-integration@^1.3.0
build_flags = build_flags =
${base_config.build_flags} ${base_config.build_flags}
-DSK_DISPLAY=1 -DSK_DISPLAY=1
@@ -89,29 +83,19 @@ build_flags =
-DLOAD_GFXFF=1 -DLOAD_GFXFF=1
-DSPI_FREQUENCY=40000000 -DSPI_FREQUENCY=40000000
; Reduce loop task stack size (only works on newer IDF Arduino core)
; -DARDUINO_LOOP_STACK_SIZE=2048
; Modify the default unusable pin mask to allow GPIO 7 (allowed to use on ESP32-PICO-V3-02)
; Unusable bits: 6, 8, 9, 10, 20
; (0ULL | _FL_BIT(6) | _FL_BIT(8) | _FL_BIT(9) | _FL_BIT(10) | _FL_BIT(20))
-DFASTLED_UNUSABLE_PIN_MASK=0x100740LL -DFASTLED_UNUSABLE_PIN_MASK=0x100740LL
; 0~39 except from 24, 28~31 are valid
; (0xFFFFFFFFFFULL & ~(0ULL | _FL_BIT(24) | _FL_BIT(28) | _FL_BIT(29) | _FL_BIT(30) | _FL_BIT(31)))
-DSOC_GPIO_VALID_GPIO_MASK=0xFF0EFFFFFF -DSOC_GPIO_VALID_GPIO_MASK=0xFF0EFFFFFF
; GPIO >= 34 are input only
; (SOC_GPIO_VALID_GPIO_MASK & ~(0ULL | _FL_BIT(34) | _FL_BIT(35) | _FL_BIT(36) | _FL_BIT(37) | _FL_BIT(38) | _FL_BIT(39)))
-DSOC_GPIO_VALID_OUTPUT_GPIO_MASK=0x30EFFFFFF -DSOC_GPIO_VALID_OUTPUT_GPIO_MASK=0x30EFFFFFF
[env:handheld_tdisplay] [env:handheld_tdisplay]
extends = base_config extends = base_config
board = esp32doit-devkit-v1 board = esp32doit-devkit-v1
lib_deps = lib_deps =
${base_config.lib_deps} ${base_config.lib_deps}
bodmer/TFT_eSPI@2.4.25 bodmer/TFT_eSPI@2.4.25
dawidchyrzynski/home-assistant-integration@^1.3.0
build_flags = build_flags =
${base_config.build_flags} ${base_config.build_flags}
-DSK_DISPLAY=1 -DSK_DISPLAY=1

View File

@@ -1,28 +0,0 @@
#include "commu_task.h"
#include "semaphore_guard.h"
CommuTask::CommuTask(const uint8_t task_core) : Task{"Communication", 4048, 1, task_core} {
mutex_ = xSemaphoreCreateMutex();
assert(mutex_ != NULL);
}
CommuTask::~CommuTask()
{
}
void CommuTask::run() {
WiFi.begin("poes", "Rijnstraat214");
while(1)
{
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
delay(100);
}
}

View File

@@ -0,0 +1,85 @@
#include "commu_task.h"
#include "semaphore_guard.h"
static byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
WiFiClient client;
HADevice device(mac, sizeof(mac));
HAMqtt mqtt(client, device);
HASensor angle("angle");
CommuTask::CommuTask(const uint8_t task_core) : Task{"Communication", 4048, 1, task_core} {
knob_state_queue_ = xQueueCreate(1, sizeof(KnobState));
assert(knob_state_queue_ != NULL);
mutex_ = xSemaphoreCreateMutex();
assert(mutex_ != NULL);
}
CommuTask::~CommuTask()
{
vQueueDelete(knob_state_queue_);
vSemaphoreDelete(mutex_);
}
QueueHandle_t CommuTask::getKnobStateQueue() {
return knob_state_queue_;
}
void CommuTask::setAngleValue(uint32_t angle)
{
angle_ = angle;
//log_d("setAngleCalled = %u", angle);
}
void CommuTask::run() {
WiFi.begin("poes", "Rijnstraat214");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
KnobState state;
device.setName("SmartKnob001");
device.setSoftwareVersion("1.0.0");
angle.setUnitOfMeasurement("°");
angle.setDeviceClass("None");
angle.setName("SmartKnob Angle");
mqtt.begin(BROKER_ADDR, BROKER_USERNAME, BROKER_PASSWORD);
uint32_t lastSensorUpdate = millis();
angle.setValue(angle_);
if(mqtt.isConnected())
{
printf("mqtt connected");
}
else{
printf("mqtt NOT connected");
}
while(1)
{
if (xQueueReceive(knob_state_queue_, &state, portMAX_DELAY) == pdFALSE) {
continue;
}
if(millis() - lastSensorUpdate > 1000)
{
angle.setValue(state.current_position);
log_d("new angle=%u", state.current_position);
lastSensorUpdate = millis();
}
mqtt.loop();
delay(10);
}
}

View File

@@ -2,10 +2,20 @@
#include <Arduino.h> #include <Arduino.h>
#include <WiFi.h> #include <WiFi.h>
#include <Client.h>
#include <ArduinoHA.h>
#include "knob_data.h" #include "knob_data.h"
#include "task.h" #include "task.h"
#define BROKER_ADDR IPAddress(192,168,4,58)
#define BROKER_USERNAME "mqtt_broker_user" // replace with your credentials
#define BROKER_PASSWORD "mqtt2022"
//HA vars
class CommuTask : public Task<CommuTask> { class CommuTask : public Task<CommuTask> {
friend class Task<CommuTask>; // Allow base Task to invoke protected run() friend class Task<CommuTask>; // Allow base Task to invoke protected run()
@@ -13,6 +23,9 @@ class CommuTask : public Task<CommuTask> {
CommuTask(const uint8_t task_core); CommuTask(const uint8_t task_core);
~CommuTask(); ~CommuTask();
void setAngleValue(uint32_t angle);
QueueHandle_t getKnobStateQueue();
protected: protected:
void run(); void run();
@@ -20,6 +33,10 @@ class CommuTask : public Task<CommuTask> {
private: private:
uint32_t angle_ =0;
SemaphoreHandle_t mutex_; SemaphoreHandle_t mutex_;
QueueHandle_t knob_state_queue_;
}; };

View File

@@ -6,7 +6,7 @@
static const uint8_t LEDC_CHANNEL_LCD_BACKLIGHT = 0; static const uint8_t LEDC_CHANNEL_LCD_BACKLIGHT = 0;
DisplayTask::DisplayTask(const uint8_t task_core) : Task{"Display", 4048, 1, task_core} { DisplayTask::DisplayTask(const uint8_t task_core) : Task{"Display", 2048, 1, task_core} {
knob_state_queue_ = xQueueCreate(1, sizeof(KnobState)); knob_state_queue_ = xQueueCreate(1, sizeof(KnobState));
assert(knob_state_queue_ != NULL); assert(knob_state_queue_ != NULL);
@@ -19,66 +19,11 @@ DisplayTask::~DisplayTask() {
vSemaphoreDelete(mutex_); vSemaphoreDelete(mutex_);
} }
static void HSV_to_RGB(float h, float s, float v, uint8_t *r, uint8_t *g, uint8_t *b)
{
int i;
float f,p,q,t;
h = fmax(0.0, fmin(360.0, h));
s = fmax(0.0, fmin(100.0, s));
v = fmax(0.0, fmin(100.0, v));
s /= 100;
v /= 100;
if(s == 0) {
// Achromatic (grey)
*r = *g = *b = round(v*255);
return;
}
h /= 60; // sector 0 to 5
i = floor(h);
f = h - i; // factorial part of h
p = v * (1 - s);
q = v * (1 - s * f);
t = v * (1 - s * (1 - f));
switch(i) {
case 0:
*r = round(255*v);
*g = round(255*t);
*b = round(255*p);
break;
case 1:
*r = round(255*q);
*g = round(255*v);
*b = round(255*p);
break;
case 2:
*r = round(255*p);
*g = round(255*v);
*b = round(255*t);
break;
case 3:
*r = round(255*p);
*g = round(255*q);
*b = round(255*v);
break;
case 4:
*r = round(255*t);
*g = round(255*p);
*b = round(255*v);
break;
default: // case 5:
*r = round(255*v);
*g = round(255*p);
*b = round(255*q);
}
}
void DisplayTask::run() { void DisplayTask::run() {
tft_.begin(); tft_.begin();
tft_.invertDisplay(1); tft_.invertDisplay(1);
spr_.setColorDepth(8);
tft_.setRotation(0); tft_.setRotation(0);
tft_.fillScreen(TFT_DARKGREEN); tft_.fillScreen(TFT_DARKGREEN);
@@ -86,7 +31,7 @@ void DisplayTask::run() {
ledcAttachPin(PIN_LCD_BACKLIGHT, LEDC_CHANNEL_LCD_BACKLIGHT); ledcAttachPin(PIN_LCD_BACKLIGHT, LEDC_CHANNEL_LCD_BACKLIGHT);
ledcWrite(LEDC_CHANNEL_LCD_BACKLIGHT, UINT16_MAX); ledcWrite(LEDC_CHANNEL_LCD_BACKLIGHT, UINT16_MAX);
spr_.setColorDepth(16); //spr_.setColorDepth(16);
if (spr_.createSprite(TFT_WIDTH, TFT_HEIGHT) == nullptr) { if (spr_.createSprite(TFT_WIDTH, TFT_HEIGHT) == nullptr) {
Serial.println("ERROR: sprite allocation failed!"); Serial.println("ERROR: sprite allocation failed!");
@@ -103,10 +48,10 @@ void DisplayTask::run() {
const uint16_t FILL_COLOR = spr_.color565(90, 18, 151); const uint16_t FILL_COLOR = spr_.color565(90, 18, 151);
const uint16_t DOT_COLOR = spr_.color565(80, 100, 200); const uint16_t DOT_COLOR = spr_.color565(80, 100, 200);
int32_t pointer_center_x = TFT_WIDTH / 2; // int32_t pointer_center_x = TFT_WIDTH / 2;
int32_t pointer_center_y = TFT_HEIGHT / 2; // int32_t pointer_center_y = TFT_HEIGHT / 2;
int32_t pointer_length_short = 10; // int32_t pointer_length_short = 10;
int32_t pointer_length_long = TFT_WIDTH / 2 - 5; // int32_t pointer_length_long = TFT_WIDTH / 2 - 5;
spr_.setTextDatum(CC_DATUM); spr_.setTextDatum(CC_DATUM);
spr_.setTextColor(TFT_WHITE); spr_.setTextColor(TFT_WHITE);
@@ -165,6 +110,7 @@ void DisplayTask::run() {
float raw_angle = left_bound - state.current_position * state.config.position_width_radians; float raw_angle = left_bound - state.current_position * state.config.position_width_radians;
float adjusted_angle = raw_angle - adjusted_sub_position; float adjusted_angle = raw_angle - adjusted_sub_position;
if (state.config.num_positions > 0 && ((state.current_position == 0 && state.sub_position_unit < 0) || (state.current_position == state.config.num_positions - 1 && state.sub_position_unit > 0))) { if (state.config.num_positions > 0 && ((state.current_position == 0 && state.sub_position_unit < 0) || (state.current_position == state.config.num_positions - 1 && state.sub_position_unit > 0))) {
spr_.fillCircle(TFT_WIDTH/2 + (RADIUS - 10) * cosf(raw_angle), TFT_HEIGHT/2 - (RADIUS - 10) * sinf(raw_angle), 5, DOT_COLOR); spr_.fillCircle(TFT_WIDTH/2 + (RADIUS - 10) * cosf(raw_angle), TFT_HEIGHT/2 - (RADIUS - 10) * sinf(raw_angle), 5, DOT_COLOR);

View File

@@ -123,7 +123,11 @@ static KnobConfig configs[] = {
}, },
}; };
InterfaceTask::InterfaceTask(const uint8_t task_core, MotorTask& motor_task, DisplayTask* display_task) : Task("Interface", 4048, 1, task_core), motor_task_(motor_task), display_task_(display_task) { InterfaceTask::InterfaceTask(const uint8_t task_core, MotorTask& motor_task, DisplayTask* display_task, CommuTask& commu_task) :
Task("Interface", 4048, 1, task_core),
motor_task_(motor_task),
display_task_(display_task),
commu_task_(commu_task){
#if SK_DISPLAY #if SK_DISPLAY
assert(display_task != nullptr); assert(display_task != nullptr);
#endif #endif
@@ -202,6 +206,7 @@ void InterfaceTask::run() {
} }
#endif #endif
#if SK_STRAIN #if SK_STRAIN
// TODO: calibrate and track (long term moving average) zero point (lower); allow calibration of set point offset // TODO: calibrate and track (long term moving average) zero point (lower); allow calibration of set point offset
const int32_t lower = 950000; const int32_t lower = 950000;
@@ -235,7 +240,7 @@ void InterfaceTask::run() {
#if SK_LEDS #if SK_LEDS
for (uint8_t i = 0; i < NUM_LEDS; i++) { for (uint8_t i = 0; i < NUM_LEDS; i++) {
leds[i] = CRGB::Red; leds[i] = CRGB::White;
} }
FastLED.show(); FastLED.show();
#endif #endif

View File

@@ -5,6 +5,7 @@
#include "display_task.h" #include "display_task.h"
#include "motor_task.h" #include "motor_task.h"
#include "commu_task.h"
#include "task.h" #include "task.h"
#define ALSCHECKINTERVAL 4000 #define ALSCHECKINTERVAL 4000
@@ -13,7 +14,7 @@ class InterfaceTask : public Task<InterfaceTask>, public ace_button::IEventHandl
friend class Task<InterfaceTask>; // Allow base Task to invoke protected run() friend class Task<InterfaceTask>; // Allow base Task to invoke protected run()
public: public:
InterfaceTask(const uint8_t task_core, MotorTask& motor_task, DisplayTask* display_task); InterfaceTask(const uint8_t task_core, MotorTask& motor_task, DisplayTask* display_task, CommuTask& commu_task);
~InterfaceTask(); ~InterfaceTask();
void handleEvent(ace_button::AceButton* button, uint8_t event_type, uint8_t button_state) override; void handleEvent(ace_button::AceButton* button, uint8_t event_type, uint8_t button_state) override;
@@ -24,6 +25,7 @@ class InterfaceTask : public Task<InterfaceTask>, public ace_button::IEventHandl
private: private:
MotorTask& motor_task_; MotorTask& motor_task_;
DisplayTask* display_task_; DisplayTask* display_task_;
CommuTask& commu_task_;
int current_config_ = 0; int current_config_ = 0;

View File

@@ -13,10 +13,10 @@ static DisplayTask* display_task_p = &display_task;
static DisplayTask* display_task_p = nullptr; static DisplayTask* display_task_p = nullptr;
#endif #endif
static MotorTask motor_task = MotorTask(0); static MotorTask motor_task = MotorTask(0);
static CommuTask commu_Task = CommuTask(1); static CommuTask commu_Task = CommuTask(0);
InterfaceTask interface_task = InterfaceTask(0, motor_task, display_task_p); InterfaceTask interface_task = InterfaceTask(0, motor_task, display_task_p, commu_Task);
static QueueHandle_t knob_state_debug_queue; static QueueHandle_t knob_state_debug_queue;
@@ -25,7 +25,7 @@ void setup() {
motor_task.begin(); motor_task.begin();
interface_task.begin(); interface_task.begin();
//commu_Task.begin(); commu_Task.begin();
#if SK_DISPLAY #if SK_DISPLAY
display_task.begin(); display_task.begin();
@@ -34,6 +34,8 @@ void setup() {
motor_task.addListener(display_task.getKnobStateQueue()); motor_task.addListener(display_task.getKnobStateQueue());
#endif #endif
motor_task.addListener(commu_Task.getKnobStateQueue());
// Create a queue and register it with motor_task to print knob state to serial (see loop() below) // Create a queue and register it with motor_task to print knob state to serial (see loop() below)
knob_state_debug_queue = xQueueCreate(1, sizeof(KnobState)); knob_state_debug_queue = xQueueCreate(1, sizeof(KnobState));
assert(knob_state_debug_queue != NULL); assert(knob_state_debug_queue != NULL);

View File

@@ -53,8 +53,8 @@ void MotorTask::run() {
// float zero_electric_offset = -0.8; // handheld 2 // float zero_electric_offset = -0.8; // handheld 2
// float zero_electric_offset = 2.93; //0.15; // 17mm test // float zero_electric_offset = 2.93; //0.15; // 17mm test
// float zero_electric_offset = 0.66; // 15mm handheld // float zero_electric_offset = 0.66; // 15mm handheld
float zero_electric_offset = 7.07; float zero_electric_offset = 5.44;
Direction foc_direction = Direction::CCW; Direction foc_direction = Direction::CW;
motor.pole_pairs = 7; motor.pole_pairs = 7;
driver.voltage_power_supply = 5; driver.voltage_power_supply = 5;

View File

@@ -6,44 +6,48 @@
#include "knob_data.h" #include "knob_data.h"
#include "task.h" #include "task.h"
enum class CommandType
enum class CommandType { {
CONFIG, CONFIG,
HAPTIC, HAPTIC,
}; };
struct HapticData { struct HapticData
{
bool press; bool press;
}; };
struct Command { struct Command
{
CommandType command_type; CommandType command_type;
union CommandData { union CommandData
{
KnobConfig config; KnobConfig config;
HapticData haptic; HapticData haptic;
}; };
CommandData data; CommandData data;
}; };
class MotorTask : public Task<MotorTask> { class MotorTask : public Task<MotorTask>
{
friend class Task<MotorTask>; // Allow base Task to invoke protected run() friend class Task<MotorTask>; // Allow base Task to invoke protected run()
public: public:
MotorTask(const uint8_t task_core); MotorTask(const uint8_t task_core);
~MotorTask(); ~MotorTask();
void setConfig(const KnobConfig& config); void setConfig(const KnobConfig &config);
void playHaptic(bool press); void playHaptic(bool press);
void addListener(QueueHandle_t queue); void addListener(QueueHandle_t queue);
protected: protected:
void run(); void run();
private: private:
QueueHandle_t queue_; QueueHandle_t queue_;
std::vector<QueueHandle_t> listeners_; std::vector<QueueHandle_t> listeners_;
void publish(const KnobState& state); void publish(const KnobState &state);
}; };