diff --git a/firmware/platformio.ini b/firmware/platformio.ini index f4c3800..40b29cc 100644 --- a/firmware/platformio.ini +++ b/firmware/platformio.ini @@ -19,138 +19,122 @@ monitor_flags = --eol=CRLF --echo --filter=esp32_exception_decoder -lib_deps = - askuric/Simple FOC @ 2.2.0 - infineon/TLV493D-Magnetic-Sensor @ 1.0.3 - bxparks/AceButton @ 1.9.1 - -build_flags = - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG +lib_deps = + askuric/Simple FOC @ 2.2.0 + infineon/TLV493D-Magnetic-Sensor @ 1.0.3 + bxparks/AceButton @ 1.9.1 +build_flags = + -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG [env:view] 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 -lib_deps = - ; askuric/Simple FOC @ 2.2.1 - ; bxparks/AceButton @ 1.9.1 - ${base_config.lib_deps} - bodmer/TFT_eSPI@2.4.25 - fastled/FastLED @ 3.5.0 - bogde/HX711 @ 0.7.5 - adafruit/Adafruit VEML7700 Library @ 1.1.1 +lib_deps = + ${base_config.lib_deps} + bodmer/TFT_eSPI@2.4.25 + fastled/FastLED @ 3.5.0 + bogde/HX711 @ 0.7.5 + adafruit/Adafruit VEML7700 Library @ 1.1.1 + dawidchyrzynski/home-assistant-integration@^1.3.0 +build_flags = + ${base_config.build_flags} + -DSK_DISPLAY=1 + -DSK_LEDS=1 + -DNUM_LEDS=8 + -DSENSOR_MT6701=1 + -DSK_STRAIN=1 + -DSK_INVERT_ROTATION=1 + -DSK_ALS=1 + + -DPIN_UH=26 + -DPIN_UL=25 + -DPIN_VH=27 + -DPIN_VL=32 + -DPIN_WH=12 + -DPIN_WL=33 + -DPIN_BUTTON_NEXT=-1 + -DPIN_BUTTON_PREV=-1 + -DPIN_SDA=15 + -DPIN_SCL=8 + -DPIN_MT_DATA=37 + -DPIN_MT_CLOCK=13 + -DPIN_MT_CSN=14 + -DPIN_LED_DATA=7 + -DPIN_LCD_BACKLIGHT=19 + + -DDESCRIPTION_FONT=Roboto_Thin_24 + -DDESCRIPTION_Y_OFFSET=20 + -DVALUE_OFFSET=30 + -DDRAW_ARC=0 + + -DUSER_SETUP_LOADED=1 + -DGC9A01_DRIVER=1 + -DCGRAM_OFFSET=1 + -DTFT_WIDTH=240 + -DTFT_HEIGHT=240 + -DTFT_MISO=-1 + -DTFT_MOSI=5 + -DTFT_SCLK=20 + -DTFT_CS=21 + -DTFT_DC=22 + -DTFT_RST=4 + -DTFT_BL=-1 + -DLOAD_GLCD=1 + -DLOAD_GFXFF=1 + -DSPI_FREQUENCY=40000000 + + + -DFASTLED_UNUSABLE_PIN_MASK=0x100740LL + + -DSOC_GPIO_VALID_GPIO_MASK=0xFF0EFFFFFF + -DSOC_GPIO_VALID_OUTPUT_GPIO_MASK=0x30EFFFFFF -build_flags = - ${base_config.build_flags} - -DSK_DISPLAY=1 - -DSK_LEDS=1 - -DNUM_LEDS=8 - -DSENSOR_MT6701=1 - -DSK_STRAIN=1 - -DSK_INVERT_ROTATION=1 - -DSK_ALS=1 - - -DPIN_UH=26 - -DPIN_UL=25 - -DPIN_VH=27 - -DPIN_VL=32 - -DPIN_WH=12 - -DPIN_WL=33 - -DPIN_BUTTON_NEXT=-1 - -DPIN_BUTTON_PREV=-1 - -DPIN_SDA=15 - -DPIN_SCL=8 - -DPIN_MT_DATA=37 - -DPIN_MT_CLOCK=13 - -DPIN_MT_CSN=14 - -DPIN_LED_DATA=7 - -DPIN_LCD_BACKLIGHT=19 - - -DDESCRIPTION_FONT=Roboto_Thin_24 - -DDESCRIPTION_Y_OFFSET=20 - -DVALUE_OFFSET=30 - -DDRAW_ARC=0 - - -DUSER_SETUP_LOADED=1 - -DGC9A01_DRIVER=1 - -DCGRAM_OFFSET=1 - -DTFT_WIDTH=240 - -DTFT_HEIGHT=240 - -DTFT_MISO=-1 - -DTFT_MOSI=5 - -DTFT_SCLK=20 - -DTFT_CS=21 - -DTFT_DC=22 - -DTFT_RST=4 - -DTFT_BL=-1 - -DLOAD_GLCD=1 - -DLOAD_GFXFF=1 - -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 - - ; 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 - ; 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 - - [env:handheld_tdisplay] extends = base_config board = esp32doit-devkit-v1 -lib_deps = - ${base_config.lib_deps} - bodmer/TFT_eSPI@2.4.25 - -build_flags = - ${base_config.build_flags} - -DSK_DISPLAY=1 - -DSK_STRAIN=0 - -DSK_LEDS=0 - - -DPIN_UH=17 - -DPIN_UL=2 - -DPIN_VH=13 - -DPIN_VL=32 - -DPIN_WH=33 - -DPIN_WL=25 - -DPIN_BUTTON_NEXT=35 - -DPIN_BUTTON_PREV=0 - -DPIN_SDA=-1 - -DPIN_SCL=-1 - -DSENSOR_MT6701=1 - -DPIN_MT_DATA=21 - -DPIN_MT_CLOCK=22 - -DPIN_MT_CSN=12 - -DPIN_LCD_BACKLIGHT=4 - - -DDESCRIPTION_FONT=FreeSans9pt7b - -DDESCRIPTION_Y_OFFSET=80 - -DVALUE_OFFSET=0 - -DDRAW_ARC=1 - - -DUSER_SETUP_LOADED=1 - -DST7789_DRIVER=1 - -DCGRAM_OFFSET=1 - -DTFT_WIDTH=135 - -DTFT_HEIGHT=240 - -DTFT_MISO=-1 - -DTFT_MOSI=19 - -DTFT_SCLK=18 - -DTFT_CS=5 - -DTFT_DC=16 - -DTFT_RST=23 - -DTFT_BL=-1 - -DLOAD_GLCD=1 - -DLOAD_GFXFF=1 - -DSPI_FREQUENCY=40000000 \ No newline at end of file +lib_deps = + ${base_config.lib_deps} + bodmer/TFT_eSPI@2.4.25 + dawidchyrzynski/home-assistant-integration@^1.3.0 +build_flags = + ${base_config.build_flags} + -DSK_DISPLAY=1 + -DSK_STRAIN=0 + -DSK_LEDS=0 + + -DPIN_UH=17 + -DPIN_UL=2 + -DPIN_VH=13 + -DPIN_VL=32 + -DPIN_WH=33 + -DPIN_WL=25 + -DPIN_BUTTON_NEXT=35 + -DPIN_BUTTON_PREV=0 + -DPIN_SDA=-1 + -DPIN_SCL=-1 + -DSENSOR_MT6701=1 + -DPIN_MT_DATA=21 + -DPIN_MT_CLOCK=22 + -DPIN_MT_CSN=12 + -DPIN_LCD_BACKLIGHT=4 + + -DDESCRIPTION_FONT=FreeSans9pt7b + -DDESCRIPTION_Y_OFFSET=80 + -DVALUE_OFFSET=0 + -DDRAW_ARC=1 + + -DUSER_SETUP_LOADED=1 + -DST7789_DRIVER=1 + -DCGRAM_OFFSET=1 + -DTFT_WIDTH=135 + -DTFT_HEIGHT=240 + -DTFT_MISO=-1 + -DTFT_MOSI=19 + -DTFT_SCLK=18 + -DTFT_CS=5 + -DTFT_DC=16 + -DTFT_RST=23 + -DTFT_BL=-1 + -DLOAD_GLCD=1 + -DLOAD_GFXFF=1 + -DSPI_FREQUENCY=40000000 diff --git a/firmware/src/CommuTask.cpp b/firmware/src/CommuTask.cpp deleted file mode 100644 index 50daf5f..0000000 --- a/firmware/src/CommuTask.cpp +++ /dev/null @@ -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); - } -} diff --git a/firmware/src/commu_task.cpp b/firmware/src/commu_task.cpp new file mode 100644 index 0000000..57ff87f --- /dev/null +++ b/firmware/src/commu_task.cpp @@ -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); + + } +} diff --git a/firmware/src/commu_task.h b/firmware/src/commu_task.h index 6ba70cb..032b47d 100644 --- a/firmware/src/commu_task.h +++ b/firmware/src/commu_task.h @@ -2,10 +2,20 @@ #include #include +#include +#include + #include "knob_data.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 { friend class Task; // Allow base Task to invoke protected run() @@ -13,13 +23,20 @@ class CommuTask : public Task { CommuTask(const uint8_t task_core); ~CommuTask(); + void setAngleValue(uint32_t angle); + QueueHandle_t getKnobStateQueue(); + protected: void run(); private: - + + uint32_t angle_ =0; SemaphoreHandle_t mutex_; + QueueHandle_t knob_state_queue_; + + }; diff --git a/firmware/src/display_task.cpp b/firmware/src/display_task.cpp index 2f986d7..9cea727 100644 --- a/firmware/src/display_task.cpp +++ b/firmware/src/display_task.cpp @@ -6,7 +6,7 @@ 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)); assert(knob_state_queue_ != NULL); @@ -19,66 +19,11 @@ DisplayTask::~DisplayTask() { 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() { tft_.begin(); tft_.invertDisplay(1); + spr_.setColorDepth(8); tft_.setRotation(0); tft_.fillScreen(TFT_DARKGREEN); @@ -86,7 +31,7 @@ void DisplayTask::run() { ledcAttachPin(PIN_LCD_BACKLIGHT, LEDC_CHANNEL_LCD_BACKLIGHT); ledcWrite(LEDC_CHANNEL_LCD_BACKLIGHT, UINT16_MAX); - spr_.setColorDepth(16); + //spr_.setColorDepth(16); if (spr_.createSprite(TFT_WIDTH, TFT_HEIGHT) == nullptr) { 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 DOT_COLOR = spr_.color565(80, 100, 200); - int32_t pointer_center_x = TFT_WIDTH / 2; - int32_t pointer_center_y = TFT_HEIGHT / 2; - int32_t pointer_length_short = 10; - int32_t pointer_length_long = TFT_WIDTH / 2 - 5; + // int32_t pointer_center_x = TFT_WIDTH / 2; + // int32_t pointer_center_y = TFT_HEIGHT / 2; + // int32_t pointer_length_short = 10; + // int32_t pointer_length_long = TFT_WIDTH / 2 - 5; spr_.setTextDatum(CC_DATUM); 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 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))) { spr_.fillCircle(TFT_WIDTH/2 + (RADIUS - 10) * cosf(raw_angle), TFT_HEIGHT/2 - (RADIUS - 10) * sinf(raw_angle), 5, DOT_COLOR); diff --git a/firmware/src/interface_task.cpp b/firmware/src/interface_task.cpp index e6ea8b1..eb8d1b1 100644 --- a/firmware/src/interface_task.cpp +++ b/firmware/src/interface_task.cpp @@ -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 assert(display_task != nullptr); #endif @@ -201,6 +205,7 @@ void InterfaceTask::run() { last_als = millis(); } #endif + #if SK_STRAIN // TODO: calibrate and track (long term moving average) zero point (lower); allow calibration of set point offset @@ -235,7 +240,7 @@ void InterfaceTask::run() { #if SK_LEDS for (uint8_t i = 0; i < NUM_LEDS; i++) { - leds[i] = CRGB::Red; + leds[i] = CRGB::White; } FastLED.show(); #endif diff --git a/firmware/src/interface_task.h b/firmware/src/interface_task.h index b0e2823..26b6e1a 100644 --- a/firmware/src/interface_task.h +++ b/firmware/src/interface_task.h @@ -5,6 +5,7 @@ #include "display_task.h" #include "motor_task.h" +#include "commu_task.h" #include "task.h" #define ALSCHECKINTERVAL 4000 @@ -13,7 +14,7 @@ class InterfaceTask : public Task, public ace_button::IEventHandl friend class Task; // Allow base Task to invoke protected run() 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(); void handleEvent(ace_button::AceButton* button, uint8_t event_type, uint8_t button_state) override; @@ -24,6 +25,7 @@ class InterfaceTask : public Task, public ace_button::IEventHandl private: MotorTask& motor_task_; DisplayTask* display_task_; + CommuTask& commu_task_; int current_config_ = 0; diff --git a/firmware/src/main.cpp b/firmware/src/main.cpp index 6c0211e..c3ef3e8 100644 --- a/firmware/src/main.cpp +++ b/firmware/src/main.cpp @@ -13,10 +13,10 @@ static DisplayTask* display_task_p = &display_task; static DisplayTask* display_task_p = nullptr; #endif 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; @@ -25,7 +25,7 @@ void setup() { motor_task.begin(); interface_task.begin(); - //commu_Task.begin(); + commu_Task.begin(); #if SK_DISPLAY display_task.begin(); @@ -34,6 +34,8 @@ void setup() { motor_task.addListener(display_task.getKnobStateQueue()); #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) knob_state_debug_queue = xQueueCreate(1, sizeof(KnobState)); assert(knob_state_debug_queue != NULL); diff --git a/firmware/src/motor_task.cpp b/firmware/src/motor_task.cpp index e9b1f66..37b7141 100644 --- a/firmware/src/motor_task.cpp +++ b/firmware/src/motor_task.cpp @@ -53,8 +53,8 @@ void MotorTask::run() { // float zero_electric_offset = -0.8; // handheld 2 // float zero_electric_offset = 2.93; //0.15; // 17mm test // float zero_electric_offset = 0.66; // 15mm handheld - float zero_electric_offset = 7.07; - Direction foc_direction = Direction::CCW; + float zero_electric_offset = 5.44; + Direction foc_direction = Direction::CW; motor.pole_pairs = 7; driver.voltage_power_supply = 5; diff --git a/firmware/src/motor_task.h b/firmware/src/motor_task.h index 9f4f87b..843aa20 100644 --- a/firmware/src/motor_task.h +++ b/firmware/src/motor_task.h @@ -6,44 +6,48 @@ #include "knob_data.h" #include "task.h" - -enum class CommandType { +enum class CommandType +{ CONFIG, HAPTIC, }; -struct HapticData { +struct HapticData +{ bool press; }; -struct Command { +struct Command +{ CommandType command_type; - union CommandData { + union CommandData + { KnobConfig config; HapticData haptic; }; CommandData data; }; -class MotorTask : public Task { +class MotorTask : public Task +{ friend class Task; // Allow base Task to invoke protected run() - public: - MotorTask(const uint8_t task_core); - ~MotorTask(); +public: + MotorTask(const uint8_t task_core); + ~MotorTask(); - void setConfig(const KnobConfig& config); - void playHaptic(bool press); + void setConfig(const KnobConfig &config); + void playHaptic(bool press); - void addListener(QueueHandle_t queue); + void addListener(QueueHandle_t queue); - protected: - void run(); +protected: + void run(); - private: - QueueHandle_t queue_; +private: + QueueHandle_t queue_; - std::vector listeners_; + std::vector listeners_; - void publish(const KnobState& state); + void publish(const KnobState &state); };