Skip to content

Initial support for RP2040 (Raspberry Pi Pico W) #50

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions firmware/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/.esphome/
/secrets.yaml
esphome_env/*
.gdb_history
.DS_Store

*.pyc
10 changes: 9 additions & 1 deletion firmware/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ clean:
esphome clean lolin_s2_mini.yaml
esphome clean lolin_s3_mini.yaml
esphome clean esp32-s3-devkitc-1.yaml
esphome clean esp32_s3_super_mini.yaml
esphome clean rpipicow.yaml
rm -rf .esphome/idedata/*
rm -rf ~/.platformio/penv
# build-esp32s2-mini:
Expand Down Expand Up @@ -69,6 +71,12 @@ lolin_s2_mini:
lolin_s3_mini:
esphome \
run lolin_s3_mini.yaml --device $(USB_ADDRESS)
rpipicow:
esphome \
run rpipicow.yaml --device $(USB_ADDRESS)
devkit:
esphome \
run esp32-s3-devkitc-1.yaml --device $(USB_ADDRESS)
run esp32-s3-devkitc-1.yaml --device $(USB_ADDRESS)
s3_super_mini:
esphome \
run esp32_s3_super_mini.yaml --device $(USB_ADDRESS)
4 changes: 2 additions & 2 deletions firmware/bambu.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ namespace bambulabs
}
}

if (doc_in["color_hex"].as<std::string>().length() != 6 && doc_in["color_hex"].as<std::string>().length() != 8) {
if (doc_in["color_hex"].as<std::string>().length() > 0 && doc_in["color_hex"].as<std::string>().length() != 6 && doc_in["color_hex"].as<std::string>().length() != 8) {
ESP_LOGE("bambu", "Invalid color_hex length (expected 6 or 8 characters)");
return {};
}
Expand All @@ -133,7 +133,7 @@ namespace bambulabs
print["command"] = "ams_filament_setting";
print["ams_id"] = ams_id;
print["tray_id"] = ams_tray;
if (doc_in["color_hex"].as<std::string>().length() == 6) {
if (doc_in["color_hex"].as<std::string>().length() > 0 && doc_in["color_hex"].as<std::string>().length() == 6) {
print["tray_color"] = doc_in["color_hex"].as<std::string>() + "FF";
}
else{
Expand Down
69 changes: 48 additions & 21 deletions firmware/common.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
---
substitutions:
name: openspool

globals:
- id: global_lan_access_code
type: std::string
restore_value: yes
- id: global_bambu_ip
type: std::string
restore_value: yes
- id: global_bambu_serial
type: std::string
restore_value: yes

esphome:
name: ${name}
name_add_mac_suffix: true
Expand All @@ -13,6 +25,7 @@ esphome:
build_flags:
- -std=gnu++14
- -DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\"
# - -DDISABLE_WATCHDOG=1
on_boot:
then:
#TODO: breahting blue studders a little bit
Expand All @@ -36,15 +49,27 @@ esphome:
id: neopixel_light
effect: none
brightness: 50%
# - delay: 100ms
# - light.addressable_set:
# id: neopixel_light
# color_brightness: 50%
# range_from: 0
# range_to: ${led_count}
# red: 50%
# green: 50%
# blue: 50%
# # - delay: 100ms
# - light.addressable_set:
# id: neopixel_light
# color_brightness: 50%
# range_from: 0
# range_to: ${led_count}
# red: 50%
# green: 50%
# blue: 50%
- text.set:
id: bambu_lan_access_code
value: !lambda |-
return id(global_lan_access_code);
- text.set:
id: bambu_ip_address
value: !lambda |-
return id(global_bambu_ip);
- text.set:
id: bambu_serial_number
value: !lambda |-
return id(global_bambu_serial);
- if:
condition:
lambda: |-
Expand All @@ -55,13 +80,13 @@ esphome:
- logger.log:
level: info
format: "Connecting to Bambu printer"
- mqtt.enable:
- ${mqtt}.enable:
id: bambu_mqtt
else:
- logger.log:
level: info
format: "Missing Bambu Credentials, skipping mqtt connect"
- mqtt.disable:
- ${mqtt}.disable:
id: bambu_mqtt
# - script.execute: set_all_leds_white
# - lambda: |-
Expand All @@ -75,14 +100,16 @@ esphome:
on_shutdown:
then:
- script.execute: set_led_off
esp32:
framework:
type: esp-idf
version: 5.3.1
platform_version: 6.9.0 # https://github.com/platformio/platform-espressif32/releases/
sdkconfig_options:
CONFIG_MBEDTLS_HKDF_C: y # Needed for bambu KDF
CONFIG_MBEDTLS_MD_C: y # Needed for bambu KDF


# esp32:
# framework:
# type: esp-idf
# version: 5.3.1
# platform_version: 6.9.0 # https://github.com/platformio/platform-espressif32/releases/
# sdkconfig_options:
# CONFIG_MBEDTLS_HKDF_C: y # Needed for bambu KDF
# CONFIG_MBEDTLS_MD_C: y # Needed for bambu KDF
# version: recommended
# sdkconfig_options:
# MBEDTLS_CERTIFICATE_BUNDLE: y
Expand All @@ -105,9 +132,9 @@ packages:
mqtt_bambu_lan: !include conf.d/mqtt_bambu_lan.yaml
filament: !include conf.d/filament.yaml
bambu_printer: !include conf.d/bambu_printer.yaml
pn532_rfid-solo: !include conf.d/pn532_rfid-solo.yaml
#pn532_rfid-solo: !include conf.d/pn532_rfid-solo.yaml # Comment if using an AMS with 4 LEDs; make sure you uncomment below also
pn532_rfid-ams-external: !include conf.d/pn532_rfid-ams-external.yaml # Uncomment if using an AMS with 4 LEDs; make sure you comment above also
automation: !include conf.d/automation.yaml
led-external: !include conf.d/led-external.yaml
ota: !include conf.d/ota.yaml
#update: !include conf.d/update.yaml
api: !include conf.d/api.yaml
Expand Down
153 changes: 153 additions & 0 deletions firmware/components/rp2040_mqtt/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Copyright (C) 2025 Drew Green (@agreenbhm)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.automation import Condition
from esphome.const import CONF_ID
from esphome.core import CORE, coroutine_with_priority
from esphome import automation
from esphome.const import (
CONF_TOPIC,
CONF_PAYLOAD,
CONF_QOS,
CONF_RETAIN
)

rp2040_mqtt_ns = cg.esphome_ns.namespace("rp2040_mqtt")
RP2040MQTTComponent = rp2040_mqtt_ns.class_("RP2040MQTT", cg.Component)
RP2040MQTTConnectedCondition = rp2040_mqtt_ns.class_("RP2040MQTTConnectedCondition", Condition)
RP2040MQTTEnableAction = rp2040_mqtt_ns.class_("RP2040MQTTEnableAction", automation.Action)
RP2040MQTTDisableAction = rp2040_mqtt_ns.class_("RP2040MQTTDisableAction", automation.Action)
RP2040MQTTPublishAction = rp2040_mqtt_ns.class_("RP2040MQTTPublishAction", automation.Action)

MULTI_CONF = True

CONF_SECURE = "secure"
CONF_MQTT_HOST = "mqtt_host"
CONF_MQTT_PORT = "mqtt_port"
CONF_AUTH = "auth"
CONF_MQTT_USER = "mqtt_user"
CONF_MQTT_PASS = "mqtt_pass"


CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(RP2040MQTTComponent),
cv.Optional(CONF_MQTT_HOST): cv.string,
cv.Optional(CONF_MQTT_PORT): cv.port,
cv.Optional(CONF_SECURE): cv.boolean,
cv.Optional(CONF_AUTH): cv.boolean,
cv.Optional(CONF_MQTT_USER): cv.string,
cv.Optional(CONF_MQTT_PASS): cv.string

}
)
.extend(cv.COMPONENT_SCHEMA)
)

@automation.register_action(
"rp2040_mqtt.enable",
RP2040MQTTEnableAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(RP2040MQTTComponent),
}
),
)

async def rp2040_mqtt_enable_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)

@automation.register_action(
"rp2040_mqtt.disable",
RP2040MQTTDisableAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(RP2040MQTTComponent),
}
),
)

async def rp2040_mqtt_disable_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)

MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(RP2040MQTTComponent),
cv.Required(CONF_TOPIC): cv.templatable(cv.publish_topic),
cv.Required(CONF_PAYLOAD): cv.templatable(cv.mqtt_payload),
cv.Optional(CONF_QOS, default=0): cv.templatable(cv.mqtt_qos),
cv.Optional(CONF_RETAIN, default=False): cv.templatable(cv.boolean),
}
)


@automation.register_action(
"rp2040_mqtt.publish", RP2040MQTTPublishAction, MQTT_PUBLISH_ACTION_SCHEMA
)
async def rp2040_mqtt_publish_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_TOPIC], args, cg.std_string)
cg.add(var.set_topic(template_))

template_ = await cg.templatable(config[CONF_PAYLOAD], args, cg.std_string)
cg.add(var.set_payload(template_))
template_ = await cg.templatable(config[CONF_QOS], args, cg.uint8)
cg.add(var.set_qos(template_))
template_ = await cg.templatable(config[CONF_RETAIN], args, bool)
cg.add(var.set_retain(template_))
return var



@automation.register_condition(
"rp2040_mqtt.connected",
RP2040MQTTConnectedCondition,
cv.Schema(
{
cv.GenerateID(): cv.use_id(RP2040MQTTComponent),
}
),
)
async def rp2040_mqtt_connected_to_code(config, condition_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(condition_id, template_arg, paren)

def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
if CONF_MQTT_HOST in config:
cg.add(var.set_mqtt_host(config[CONF_MQTT_HOST]))
if CONF_MQTT_PORT in config:
cg.add(var.set_mqtt_port(config[CONF_MQTT_PORT]))
if CONF_SECURE in config:
cg.add(var.set_secure(config[CONF_SECURE]))
if CONF_AUTH in config:
cg.add(var.set_authenticate(config[CONF_AUTH]))
if CONF_MQTT_USER in config:
cg.add(var.set_mqtt_user(config[CONF_MQTT_USER]))
if CONF_MQTT_PASS in config:
cg.add(var.set_mqtt_password(config[CONF_MQTT_PASS]))
# if CORE.is_rp2040:
# cg.add_library("mobizt/ESP_SSLClient", None)
cg.add_library("mobizt/ESP_SSLClient", None)
cg.add_library("arduino-libraries/ArduinoMqttClient", None)


yield cg.register_component(var, config)
Loading