Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# -----
# PLEASE DO NOT EDIT THIS FILE. EDIT printer.cfg INSTEAD.
# UPDATES WILL RESET THIS FILE. YOUR EDITS WILL BE LOST WHEN UPDATING.
# -----

[fan_generic aux_fan]
pin: PD15
tachometer_pin: PD14

[fan_generic case_fan]
pin: PD17
tachometer_pin: PD16

[servo case_servo]
pin: PB7
initial_angle: 90.0

[led case]
white_pin: PB5
initial_WHITE: 1

[gcode_button case_servo_sensor]
pin: PB2
press_gcode:
UPDATE_DELAYED_GCODE ID=case_servo_timeout DURATION=0
G4 P400 ; We have no way to detect when the fan cover is fully open. Instead, the sensor triggers somewhere halfway, and around 400ms is needed to fully open it.
SET_SERVO SERVO=case_servo ANGLE=90
release_gcode:
UPDATE_DELAYED_GCODE ID=case_servo_timeout DURATION=0
SET_SERVO SERVO=case_servo ANGLE=90

[delayed_gcode case_servo_timeout]
gcode:
SET_SERVO SERVO=case_servo ANGLE=90
RESPOND TYPE=error MSG="Servo timeout: sensor did not change"

[gcode_macro EXHAUST_OPEN]
gcode:
{% if printer["gcode_button case_servo_sensor"].state == "PRESSED" %} ; Currently closed
RESPOND MSG="Opening exhaust cover"
UPDATE_DELAYED_GCODE ID=case_servo_timeout DURATION=5
SET_SERVO SERVO=case_servo ANGLE=135
{% endif %}

[gcode_macro EXHAUST_CLOSE]
gcode:
{% if printer["gcode_button case_servo_sensor"].state == "RELEASED" %} ; Currently open
RESPOND MSG="Closing exhaust cover"
UPDATE_DELAYED_GCODE ID=case_servo_timeout DURATION=5
SET_SERVO SERVO=case_servo ANGLE=45
{% endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -364,60 +364,13 @@ runout_gcode:
PAUSE
{% endif %}

[led case]
white_pin: PB5
initial_WHITE: 1

[temperature_sensor chamber]
sensor_pin: PB13
sensor_type: NTC 100K beta 3950
pullup_resistor: 22000
min_temp: 0
max_temp: 125

[fan_generic aux_fan]
pin: PD15
tachometer_pin: PD14

[fan_generic case_fan]
pin: PD17
tachometer_pin: PD16

[servo case_servo]
pin: PB7
initial_angle: 90.0

[gcode_button case_servo_sensor]
pin: PB2
press_gcode:
UPDATE_DELAYED_GCODE ID=case_servo_timeout DURATION=0
G4 P400 ; We have no way to detect when the fan cover is fully open. Instead, the sensor triggers somewhere halfway, and around 400ms is needed to fully open it.
SET_SERVO SERVO=case_servo ANGLE=90
release_gcode:
UPDATE_DELAYED_GCODE ID=case_servo_timeout DURATION=0
SET_SERVO SERVO=case_servo ANGLE=90

[delayed_gcode case_servo_timeout]
gcode:
SET_SERVO SERVO=case_servo ANGLE=90
RESPOND TYPE=error MSG="Servo timeout: sensor did not change"

[gcode_macro EXHAUST_OPEN]
gcode:
{% if printer["gcode_button case_servo_sensor"].state == "PRESSED" %} ; Currently closed
RESPOND MSG="Opening exhaust cover"
UPDATE_DELAYED_GCODE ID=case_servo_timeout DURATION=5
SET_SERVO SERVO=case_servo ANGLE=135
{% endif %}

[gcode_macro EXHAUST_CLOSE]
gcode:
{% if printer["gcode_button case_servo_sensor"].state == "RELEASED" %} ; Currently open
RESPOND MSG="Closing exhaust cover"
UPDATE_DELAYED_GCODE ID=case_servo_timeout DURATION=5
SET_SERVO SERVO=case_servo ANGLE=45
{% endif %}

[temperature_fan mainboard]
pin: PG15
tachometer_pin: PB9
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -782,9 +782,9 @@ gcode:

{% if index == 1 %} # Part cooling fan
M006 S{speed}
{% elif index == 2 %} # Aux cooling fan
{% elif index == 2 and 'fan_generic aux_fan' in printer %} # Aux cooling fan
SET_FAN_SPEED FAN=aux_fan SPEED={nspeed}
{% elif index == 3 %} # Exhaust fan
{% elif index == 3 and 'fan_generic case_fan' in printer %} # Exhaust fan
SET_FAN_SPEED FAN=case_fan SPEED={nspeed}
{% else %}
{action_raise_error("Invalid fan index")}
Expand Down
13 changes: 13 additions & 0 deletions meta-opencentauri/recipes-apps/klipper/kalico_2026.02.00.bb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ SRC_URI += " \
file://client.cfg \
"

SRC_URI:append:centauri-carbon-1 = " file://canvas-toolhead.cfg"
SRC_URI:append:centauri-carbon-2 = " file://enclosed.cfg"

inherit python3-dir update-rc.d

RDEPENDS:${PN} = " \
Expand Down Expand Up @@ -113,6 +116,16 @@ do_install() {
install -m 0755 ${UNPACKDIR}/klipper-init-d ${D}${sysconfdir}/init.d/klipper
}

do_install:append:centauri-carbon-1() {
install -d ${D}${sysconfdir}/klipper/config/extras-readonly
install -m 0644 ${UNPACKDIR}/canvas-toolhead.cfg ${D}${sysconfdir}/klipper/config/extras-readonly/
}

do_install:append:centauri-carbon-2() {
install -d ${D}${sysconfdir}/klipper/config/extras-readonly
install -m 0644 ${UNPACKDIR}/enclosed.cfg ${D}${sysconfdir}/klipper/config/extras-readonly/
}

FILES:${PN} = " \
${datadir}/klipper \
${sysconfdir}/init.d/klipper \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@
### END INIT INFO

USTREAMER_EXEC="/usr/bin/ustreamer"
USTREAMER_ARGS="-r 864x480 -c HW -m MJPEG -b 1 -w 1 -f 10 -l --host=0.0.0.0 --allow-origin=*"
CAMERA_DEVICE="/dev/video0"
USTREAMER_ARGS="-d $CAMERA_DEVICE -r 864x480 -c HW -m MJPEG -b 1 -w 1 -f 10 -l --host=0.0.0.0 --allow-origin=*"
PIDFILE="/var/run/ustreamer.pid"

case "$1" in
start)
if [ ! -c "$CAMERA_DEVICE" ]; then
echo "Skipping ustreamer: camera device $CAMERA_DEVICE is unavailable."
exit 0
fi

echo "Starting ustreamer..."
start-stop-daemon -S -b -m -p $PIDFILE \
-x $USTREAMER_EXEC -- $USTREAMER_ARGS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ SRC_URI = " \
file://config_manager.py \
file://build-klipper-var-config.sh \
file://default.conf \
file://default-machine.conf \
"

S = "${UNPACKDIR}"
Expand All @@ -19,17 +20,19 @@ do_install() {
sed -i -e 's,@MACHINE@,${MACHINE},g' ${D}${bindir}/build-klipper-var-config

install -d ${D}${sysconfdir}/klipper/config
install -m 0644 ${S}/default.conf ${D}${sysconfdir}/klipper/config/cosmos.conf
install -m 0644 ${S}/default-machine.conf ${D}${sysconfdir}/klipper/config/cosmos.conf

install -d ${D}${datadir}/config-manager
install -m 0644 ${S}/default.conf ${D}${datadir}/config-manager/default.conf
install -m 0644 ${S}/default-machine.conf ${D}${datadir}/config-manager/default-machine.conf
}

FILES:${PN} = " \
${bindir}/config-manager \
${bindir}/build-klipper-var-config \
${sysconfdir}/klipper/config/cosmos.conf \
${datadir}/config-manager/default.conf \
${datadir}/config-manager/default-machine.conf \
"

RDEPENDS:${PN} = "python3-core"
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ toolhead_led=$(get_config_value toolhead_led)
elegoo_canvas=$("${CONFIG_MANAGER}" extras elegoo_canvas)
check_for_updates=$("${CONFIG_MANAGER}" update check_for_updates)
release=$("${CONFIG_MANAGER}" update release)
enclosed=$("${CONFIG_MANAGER}" extras enclosed)

mkdir -p "${OUTPUT_DIR}"

Expand Down Expand Up @@ -63,6 +64,10 @@ if [ "${elegoo_canvas}" = "True" ]; then
echo "[include ../extras-readonly/canvas.cfg]" >> "${EXTRAS_OUTPUT_FILE}"
fi

if [ "${enclosed}" = "True" ]; then
echo "[include ../extras-readonly/enclosed.cfg]" >> "${EXTRAS_OUTPUT_FILE}"
fi

cat > "${MOONRAKER_UPDATE_FILE}" <<EOF
# Generated on startup from cosmos.conf
# Do not edit this file directly. Instead, edit cosmos.conf and reboot to apply changes.
Expand All @@ -79,5 +84,4 @@ if [ "${check_for_updates}" = "True" ]; then
else
echo "channel: stable" >> "${MOONRAKER_UPDATE_FILE}"
fi
fi

fi
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# OpenCentauri COSMOS settings.
# Changes to these settings require rebooting the entire machine to apply.
# Power cycle the machine or run the REBOOT_MACHINE macro after editing.

[ui]
# User interface used on the built in screen. Options: grumpyscreen, none.
screen_ui = grumpyscreen
# User interface used for the webui. Options: mainsail, fluidd.
web_ui = mainsail
# Brightness of the built in screen. Range: 0-100.
screen_brightness = 100

[update]
# Update channel used by the COSMOS updater. Options: stable, nightly.
release = stable
# Check for updates automatically on startup. Options: True, False.
check_for_updates = True

[extras]
# Enable support for the CANVAS unit. Also enables the AFC subsystem.
elegoo_canvas = False

[klipper]
# Keep the camera LED state in sync with the chamber LED.
sync_camera_led_to_chamber_led = False
# Turn the camera LED on automatically when Klipper starts.
camera_led_default_on = True
# Allow printing before the initial calibration checks have passed.
bypass_calibration = False
# Minutes to wait after the bed reaches temperature before starting a print. Range: 0-30 minutes.
heatsoak = 1
# Probe only the print area for each print instead of loading the default bed mesh. Requires nozzle_z_homing to be enabled.
adaptive_mesh = False
# Prime the nozzle near the print area before each print.
adaptive_purge = True
# Unload filament automatically when a print finishes.
unload_after_print = False
# Clean the nozzle automatically when a print finishes.
clean_nozzle_after_print = True
# Use the nozzle and load cell probe for Z homing.
nozzle_z_homing = False
# Drop the bed to this height in millimeters when a print finishes. Range: 0-256.
z_ideal_lifting_distance = 170
# Hotend temperature in Celsius used during the full calibration workflow. Range: 200-300.
full_calibrate_hotend_temperature = 250
# Bed temperature in Celsius used during the full calibration workflow. Range: 40-100.
full_calibrate_bed_temperature = 60
# Turn on Toolhead LED for printing and loading filament
toolhead_led = False
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# OpenCentauri COSMOS settings.
# Changes to these settings require rebooting the entire machine to apply.
# Power cycle the machine or run the REBOOT_MACHINE macro after editing.

[ui]
# User interface used on the built in screen. Options: grumpyscreen, none.
screen_ui = grumpyscreen
# User interface used for the webui. Options: mainsail, fluidd.
web_ui = mainsail
# Brightness of the built in screen. Range: 0-100.
screen_brightness = 100

[update]
# Update channel used by the COSMOS updater. Options: stable, nightly.
release = stable
# Check for updates automatically on startup. Options: True, False.
check_for_updates = True

[extras]
# Enable support for the CANVAS unit. Also enables the AFC subsystem.
elegoo_canvas = False
# Enable the aux fan, exhaust fan and chamber light. Available only on the CC2 and CC2C.
enclosed = False

[klipper]
# Allow printing before the initial calibration checks have passed.
bypass_calibration = False
# Minutes to wait after the bed reaches temperature before starting a print. Range: 0-30 minutes.
heatsoak = 1
# Probe only the print area for each print instead of loading the default bed mesh. Requires nozzle_z_homing to be enabled.
adaptive_mesh = False
# Prime the nozzle near the print area before each print.
adaptive_purge = True
# Unload filament automatically when a print finishes.
unload_after_print = False
# Clean the nozzle automatically when a print finishes.
clean_nozzle_after_print = True
# Use the nozzle and load cell probe for Z homing.
nozzle_z_homing = False
# Drop the bed to this height in millimeters when a print finishes. Range: 0-256.
z_ideal_lifting_distance = 170
# Hotend temperature in Celsius used during the full calibration workflow. Range: 200-300.
full_calibrate_hotend_temperature = 250
# Bed temperature in Celsius used during the full calibration workflow. Range: 40-100.
full_calibrate_bed_temperature = 60
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
},
'extras': {
'elegoo_canvas': ['True', 'False'],
'enclosed': ['True', 'False'],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would carbon_version make it more obvious which machines this is relevant too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, but i don't really like that they used 'carbon' for the name of the enclosed version

},
'klipper': {
'sync_camera_led_to_chamber_led': ['True', 'False'],
Expand All @@ -33,6 +34,7 @@

VARIABLE_CONFIG_PATH = '/etc/klipper/config/cosmos.conf'
DEFAULT_CONFIG_PATH = '/usr/share/config-manager/default.conf'
MACHINE_CONFIG_PATH = '/usr/share/config-manager/default-machine.conf'

def validate_config(config : dict):
for section, options in VALIDATORS.items():
Expand Down Expand Up @@ -147,25 +149,30 @@ def merge_configs(default_config : dict, user_config : dict) -> dict:
return default_config

def main(section : str, option : str, value : str|None = None):
default_config = load_config(DEFAULT_CONFIG_PATH)
default_comments = load_config_comments(DEFAULT_CONFIG_PATH)
default_header = load_config_header(DEFAULT_CONFIG_PATH)
machine_config = load_config(MACHINE_CONFIG_PATH)
machine_comments = load_config_comments(MACHINE_CONFIG_PATH)
machine_header = load_config_header(MACHINE_CONFIG_PATH)
user_config = load_config(VARIABLE_CONFIG_PATH)
if value is not None:
if section not in user_config:
user_config[section] = {}
user_config[section][option] = value
normalize_boolean_values(user_config)
validate_config(user_config)
merged_config = merge_configs(default_config, user_config)
merged_config = merge_configs(machine_config, user_config)

if user_config != merged_config or config_needs_update(VARIABLE_CONFIG_PATH, merged_config, default_comments, default_header):
save_config(VARIABLE_CONFIG_PATH, merged_config, default_comments, default_header)
if user_config != merged_config or config_needs_update(VARIABLE_CONFIG_PATH, merged_config, machine_comments, machine_header):
save_config(VARIABLE_CONFIG_PATH, merged_config, machine_comments, machine_header)

if section not in merged_config or option not in merged_config[section]:
raise ValueError(f"Option '{option}' not found in section '{section}'")
if section in merged_config and option in merged_config[section]:
result = merged_config[section][option]
else:
global_config = load_config(DEFAULT_CONFIG_PATH)
if section not in global_config or option not in global_config[section]:
raise ValueError(f"Option '{option}' not found in section '{section}'")
result = global_config[section][option]

print(merged_config[section][option], end='')
print(result, end='')

if __name__ == "__main__":
if len(sys.argv) not in (3, 4):
Expand Down
Loading
Loading