diff --git a/.storage/lovelace.ender5_printer b/.storage/lovelace.ender5_printer
index 1c320a4d..806a2122 100644
--- a/.storage/lovelace.ender5_printer
+++ b/.storage/lovelace.ender5_printer
@@ -8,33 +8,37 @@
{
"title": "Ender 5",
"path": "printer",
+ "icon": "mdi:printer-3d-nozzle",
"type": "sections",
"max_columns": 3,
- "badges": [
- {
- "type": "entity",
- "entity": "sensor.octoprint_print_status"
- }
- ],
+ "subview": false,
"sections": [
{
"type": "grid",
"cards": [
{
"type": "heading",
- "heading": "Controls",
- "heading_style": "title"
- },
- {
- "type": "horizontal-stack",
- "cards": [
+ "icon": "mdi:printer",
+ "heading_style": "title",
+ "heading": "Ender 5",
+ "badges": [
+ {
+ "type": "entity",
+ "show_state": true,
+ "show_icon": false,
+ "entity": "sensor.octoprint_print_status"
+ },
{
"type": "button",
- "entity": "switch.octoprint_pause_print",
- "name": "Pause",
"icon": "mdi:pause",
+ "text": "Pause",
+ "color": "",
"tap_action": {
- "action": "toggle"
+ "action": "perform-action",
+ "perform_action": "switch.turn_on",
+ "target": {
+ "entity_id": "switch.octoprint_pause_print"
+ }
},
"visibility": [
{
@@ -51,11 +55,15 @@
},
{
"type": "button",
- "entity": "switch.octoprint_pause_print",
- "name": "Resume",
"icon": "mdi:play",
+ "text": "Resume",
+ "color": "",
"tap_action": {
- "action": "toggle"
+ "action": "perform-action",
+ "perform_action": "switch.turn_off",
+ "target": {
+ "entity_id": "switch.octoprint_pause_print"
+ }
},
"visibility": [
{
@@ -67,9 +75,9 @@
},
{
"type": "button",
- "entity": "button.octoprint_cancel_print",
- "name": "Cancel",
- "icon": "mdi:stop-circle-outline",
+ "icon": "mdi:stop",
+ "text": "Cancel",
+ "color": "#F44336",
"tap_action": {
"action": "perform-action",
"perform_action": "button.press",
@@ -89,295 +97,420 @@
]
},
{
- "type": "vertical-stack",
- "cards": [
- {
- "type": "button",
- "entity": "switch.octoprint_connect_to_printer",
- "name": "Connect",
- "icon": "mdi:lan-connect",
- "show_state": false,
- "tap_action": {
- "action": "toggle"
- },
- "visibility": [
- {
- "condition": "state",
- "entity": "binary_sensor.octoprint_connected",
- "state": "off"
- }
- ]
+ "type": "button",
+ "icon": "mdi:alert-octagon",
+ "text": "Emergency stop",
+ "color": "#F44336",
+ "tap_action": {
+ "action": "perform-action",
+ "perform_action": "button.press",
+ "target": {
+ "entity_id": "button.octoprint_emergency_stop"
},
- {
- "type": "button",
- "entity": "switch.octoprint_connect_to_printer",
- "name": "Disconnect",
- "icon": "mdi:lan-disconnect",
- "show_state": false,
- "tap_action": {
- "action": "toggle"
- },
- "visibility": [
- {
- "condition": "state",
- "entity": "binary_sensor.octoprint_connected",
- "state": "on"
- }
- ]
+ "confirmation": {
+ "text": "Emergency stop the printer NOW?"
}
- ]
+ }
}
]
},
{
- "type": "button",
- "entity": "button.octoprint_emergency_stop",
- "name": "EMERGENCY STOP",
- "icon": "mdi:alert-octagon",
- "tap_action": {
- "action": "perform-action",
- "perform_action": "button.press",
- "target": {
- "entity_id": "button.octoprint_emergency_stop"
- },
- "confirmation": {
- "text": "Emergency stop the printer now?"
- }
- }
- },
- {
- "type": "grid",
- "columns": 2,
- "square": false,
+ "type": "horizontal-stack",
"cards": [
{
"type": "custom:button-card",
- "entity": "sensor.octoprint_print_status",
- "name": "Nozzle",
- "icon": "mdi:thermometer-lines",
- "label": "[[[ return states['sensor.octoprint_tool_0_temperature'].state + '° / ' + states['sensor.octoprint_tool_0_target'].state + '°'; ]]]",
- "color": "#E53935",
+ "entity": "sensor.octoprint_tool_0_temperature",
+ "show_name": false,
+ "show_state": false,
+ "show_icon": false,
+ "tap_action": {
+ "action": "more-info"
+ },
+ "custom_fields": {
+ "content": "[[[\n const sec = 'var(--secondary-text-color)';\n const pri = 'var(--primary-text-color)';\n return `\n
\n
\n \n Nozzle\n
\n
${Math.round(parseFloat(states['sensor.octoprint_tool_0_temperature']?.state) || 0) + '\\u00B0C / target ' + Math.round(parseFloat(states['sensor.octoprint_tool_0_target']?.state) || 0) + '\\u00B0C'}\n
\n `;\n]]]"
+ },
"styles": {
"card": [
{
- "height": "74px",
- "padding": "6px 10px"
+ "background": "var(--ha-card-background, var(--card-background-color))"
+ },
+ {
+ "border-radius": "12px"
+ },
+ {
+ "padding": "0"
+ },
+ {
+ "height": "74px"
+ },
+ {
+ "position": "relative"
+ },
+ {
+ "box-shadow": "none"
+ },
+ {
+ "border": "1px solid rgba(var(--rgb-primary-text-color), 0.08)"
}
],
- "name": [
- {
- "font-size": "12px",
- "justify-self": "start",
- "opacity": "0.8"
- }
- ],
- "icon": [
- {
- "color": "#E53935",
- "width": "26px"
- }
- ],
- "label": [
- {
- "font-size": "17px",
- "font-weight": "600",
- "justify-self": "start",
- "color": "#E53935"
- }
- ]
+ "custom_fields": {
+ "content": [
+ {
+ "position": "absolute"
+ },
+ {
+ "inset": "0"
+ },
+ {
+ "padding": "0"
+ }
+ ]
+ }
}
},
{
"type": "custom:button-card",
- "entity": "sensor.octoprint_print_status",
- "name": "Bed",
- "icon": "mdi:radiator",
- "label": "[[[ return states['sensor.octoprint_bed_temperature'].state + '° / ' + states['sensor.octoprint_bed_target'].state + '°'; ]]]",
- "color": "#FB8C00",
+ "entity": "sensor.octoprint_bed_temperature",
+ "show_name": false,
+ "show_state": false,
+ "show_icon": false,
+ "tap_action": {
+ "action": "more-info"
+ },
+ "custom_fields": {
+ "content": "[[[\n const sec = 'var(--secondary-text-color)';\n const pri = 'var(--primary-text-color)';\n return `\n \n
\n \n Print bed\n
\n
${Math.round(parseFloat(states['sensor.octoprint_bed_temperature']?.state) || 0) + '\\u00B0C / target ' + Math.round(parseFloat(states['sensor.octoprint_bed_target']?.state) || 0) + '\\u00B0C'}\n
\n `;\n]]]"
+ },
"styles": {
"card": [
{
- "height": "74px",
- "padding": "6px 10px"
+ "background": "var(--ha-card-background, var(--card-background-color))"
+ },
+ {
+ "border-radius": "12px"
+ },
+ {
+ "padding": "0"
+ },
+ {
+ "height": "74px"
+ },
+ {
+ "position": "relative"
+ },
+ {
+ "box-shadow": "none"
+ },
+ {
+ "border": "1px solid rgba(var(--rgb-primary-text-color), 0.08)"
}
],
- "name": [
- {
- "font-size": "12px",
- "justify-self": "start",
- "opacity": "0.8"
- }
- ],
- "icon": [
- {
- "color": "#FB8C00",
- "width": "26px"
- }
- ],
- "label": [
- {
- "font-size": "17px",
- "font-weight": "600",
- "justify-self": "start",
- "color": "#FB8C00"
- }
- ]
+ "custom_fields": {
+ "content": [
+ {
+ "position": "absolute"
+ },
+ {
+ "inset": "0"
+ },
+ {
+ "padding": "0"
+ }
+ ]
+ }
}
},
{
"type": "custom:button-card",
- "entity": "sensor.octoprint_print_status",
- "name": "Time left",
- "icon": "mdi:timer-outline",
- "label": "[[[ const t = Number(states['sensor.octoprint_print_time_left'].state); return isNaN(t) ? '--' : new Date(t * 1000).toISOString().substr(11, 8); ]]]",
- "color": "#43A047",
+ "entity": "sensor.octoprint_print_time_left",
+ "show_name": false,
+ "show_state": false,
+ "show_icon": false,
+ "tap_action": {
+ "action": "more-info"
+ },
+ "custom_fields": {
+ "content": "[[[\n const sec = 'var(--secondary-text-color)';\n const pri = 'var(--primary-text-color)';\n const t = parseFloat(states['sensor.octoprint_print_time_left']?.state) || 0;\n const h = Math.floor(t / 3600);\n const m = Math.round((t % 3600) / 60);\n let primary = '--';\n if (t > 0) {\n primary = h > 0 ? `${h}h ${m}m` : `${m}m`;\n }\n let secondary = '';\n const et = states['sensor.octoprint_approximate_completion_time']?.state;\n if (et && !['unknown','unavailable',''].includes(et)) {\n const d = new Date(et);\n secondary = `Done: ~${d.getHours().toString().padStart(2,'0')}:${d.getMinutes().toString().padStart(2,'0')}`;\n }\n return `\n \n
\n \n Time left\n
\n
${primary}\n
${secondary}\n
\n `;\n ]]]"
+ },
"styles": {
"card": [
{
- "height": "74px",
- "padding": "6px 10px"
+ "background": "var(--ha-card-background, var(--card-background-color))"
+ },
+ {
+ "border-radius": "12px"
+ },
+ {
+ "padding": "0"
+ },
+ {
+ "height": "74px"
+ },
+ {
+ "position": "relative"
+ },
+ {
+ "box-shadow": "none"
+ },
+ {
+ "border": "1px solid rgba(var(--rgb-primary-text-color), 0.08)"
}
],
- "name": [
- {
- "font-size": "12px",
- "justify-self": "start",
- "opacity": "0.8"
- }
- ],
- "icon": [
- {
- "color": "#43A047",
- "width": "26px"
- }
- ],
- "label": [
- {
- "font-size": "17px",
- "font-weight": "600",
- "justify-self": "start",
- "color": "#43A047"
- }
- ]
+ "custom_fields": {
+ "content": [
+ {
+ "position": "absolute"
+ },
+ {
+ "inset": "0"
+ },
+ {
+ "padding": "0"
+ }
+ ]
+ }
}
},
{
"type": "custom:button-card",
- "entity": "sensor.octoprint_print_status",
- "name": "Height",
- "icon": "mdi:arrow-up-bold",
- "label": "[[[ return states['sensor.octoprint_current_z'].state + ' mm'; ]]]",
- "color": "#1E88E5",
+ "entity": "sensor.octoprint_current_z",
+ "show_name": false,
+ "show_state": false,
+ "show_icon": false,
+ "tap_action": {
+ "action": "more-info"
+ },
+ "custom_fields": {
+ "content": "[[[\n const sec = 'var(--secondary-text-color)';\n const pri = 'var(--primary-text-color)';\n return `\n \n
\n \n Height\n
\n
${states['sensor.octoprint_current_z']?.state + ' mm'}\n
\n `;\n]]]"
+ },
"styles": {
"card": [
{
- "height": "74px",
- "padding": "6px 10px"
+ "background": "var(--ha-card-background, var(--card-background-color))"
+ },
+ {
+ "border-radius": "12px"
+ },
+ {
+ "padding": "0"
+ },
+ {
+ "height": "74px"
+ },
+ {
+ "position": "relative"
+ },
+ {
+ "box-shadow": "none"
+ },
+ {
+ "border": "1px solid rgba(var(--rgb-primary-text-color), 0.08)"
}
],
- "name": [
- {
- "font-size": "12px",
- "justify-self": "start",
- "opacity": "0.8"
- }
- ],
- "icon": [
- {
- "color": "#1E88E5",
- "width": "26px"
- }
- ],
- "label": [
- {
- "font-size": "17px",
- "font-weight": "600",
- "justify-self": "start",
- "color": "#1E88E5"
- }
- ]
+ "custom_fields": {
+ "content": [
+ {
+ "position": "absolute"
+ },
+ {
+ "inset": "0"
+ },
+ {
+ "padding": "0"
+ }
+ ]
+ }
}
}
]
},
{
- "type": "gauge",
+ "type": "custom:button-card",
"entity": "sensor.octoprint_print_progress",
- "unit": "%",
- "min": 0,
- "max": 100,
- "needle": false,
- "severity": {
- "green": 65,
- "yellow": 25,
- "red": 0
+ "show_name": false,
+ "show_state": false,
+ "show_icon": false,
+ "tap_action": {
+ "action": "none"
+ },
+ "custom_fields": {
+ "content": "[[[\n const pct = Math.round(parseFloat(states['sensor.octoprint_print_progress']?.state) || 0);\n let file = states['sensor.octoprint_print_file']?.state || '--';\n if (['unknown','unavailable'].includes(file)) file = 'No file';\n file = file.replace(/\\.gcode$/i, '');\n return `\n \n
\n \n Print progress\n
\n
\n ${pct}%\n ${file}\n
\n
\n
\n `;\n ]]]"
+ },
+ "styles": {
+ "card": [
+ {
+ "background": "var(--ha-card-background, var(--card-background-color))"
+ },
+ {
+ "border-radius": "12px"
+ },
+ {
+ "padding": "0"
+ },
+ {
+ "height": "74px"
+ },
+ {
+ "position": "relative"
+ },
+ {
+ "box-shadow": "none"
+ },
+ {
+ "height": "100px"
+ }
+ ],
+ "custom_fields": {
+ "content": [
+ {
+ "position": "absolute"
+ },
+ {
+ "inset": "0"
+ },
+ {
+ "padding": "0"
+ }
+ ]
+ }
}
},
{
- "type": "markdown",
- "content": "{% set f = states('sensor.octoprint_print_file') %}\n**{{ f.replace('.gcode', '') if f not in ['unknown', 'unavailable'] else 'No file loaded' }}**\n\n{{ states('sensor.octoprint_print_status') }}{% set t = states('sensor.octoprint_approximate_completion_time') %}{% if t not in ['unknown', 'unavailable'] %} · ETA {{ (t | as_datetime | as_local).strftime('%H:%M') }}{% endif %}"
- }
- ]
- },
- {
- "type": "grid",
- "cards": [
- {
- "type": "heading",
- "heading": "Monitor",
- "heading_style": "title"
- },
- {
- "type": "custom:webrtc-camera",
- "entity": "camera.endercamera_duckdns_org",
- "mode": "mse",
- "url": "octoprint",
- "muted": true
- },
- {
- "type": "custom:mushroom-light-card",
- "entity": "light.3d_printer_lights",
- "name": "Printer lights",
- "show_brightness_control": true,
- "collapsible_controls": true
+ "type": "vertical-stack",
+ "cards": [
+ {
+ "type": "custom:webrtc-camera",
+ "url": "octoprint",
+ "mode": "mse",
+ "style": "border-radius: 12px 12px 0 0; overflow: hidden;"
+ },
+ {
+ "type": "custom:mushroom-light-card",
+ "entity": "light.3d_printer_lights",
+ "name": "Lamp",
+ "icon": "mdi:lightbulb",
+ "show_brightness_control": true,
+ "layout": "horizontal"
+ }
+ ]
},
{
"type": "custom:apexcharts-card",
- "graph_span": "1h",
- "update_interval": 15,
"header": {
- "title": "Temperatures (last hour)",
- "show": true
+ "show": false
},
+ "graph_span": "1h",
"series": [
{
"entity": "sensor.octoprint_tool_0_temperature",
"name": "Nozzle",
- "type": "line",
+ "color": "#E53935",
"stroke_width": 2,
- "color": "#E53935"
+ "extend_to": "now"
},
{
"entity": "sensor.octoprint_bed_temperature",
"name": "Bed",
- "type": "line",
+ "color": "#FB8C00",
"stroke_width": 2,
- "color": "#FB8C00"
+ "extend_to": "now"
}
],
"apex_config": {
"chart": {
- "height": 220
+ "height": 130,
+ "toolbar": {
+ "show": false
+ }
+ },
+ "stroke": {
+ "curve": "smooth"
+ },
+ "grid": {
+ "borderColor": "rgba(var(--rgb-primary-text-color), 0.05)"
},
"yaxis": {
"min": 0,
- "max": 280
+ "max": 280,
+ "labels": {
+ "style": {
+ "fontSize": "9px"
+ },
+ "maxWidth": 28
+ }
+ },
+ "xaxis": {
+ "labels": {
+ "style": {
+ "fontSize": "9px"
+ }
+ },
+ "datetimeFormatter": {
+ "hour": "HH:mm",
+ "minute": "HH:mm"
+ }
+ },
+ "tooltip": {
+ "x": {
+ "format": "HH:mm"
+ }
+ },
+ "legend": {
+ "show": true,
+ "fontSize": "10px",
+ "horizontalAlign": "left",
+ "offsetX": 28
}
}
},
{
- "type": "markdown",
- "content": "**Today**\n\nPrints: {{ states('sensor.octoprint_printer_prints_today') }} · Time: {{ states('sensor.octoprint_printer_print_time_today') }} h\n\nFilament: {{ (states('sensor.octoprint_filament_daily') | float(0) / 10) | round(1) }} m · Serial health: {{ (states('sensor.octoprint_serial_health_ratio') | float(0) * 100) | round(0) }}%"
+ "type": "custom:button-card",
+ "entity": "binary_sensor.octoprint_connected",
+ "show_name": false,
+ "show_icon": false,
+ "tap_action": {
+ "action": "none"
+ },
+ "custom_fields": {
+ "content": "[[[\n const connected = states['binary_sensor.octoprint_connected']?.state === 'on';\n const printing = states['binary_sensor.octoprint_printing']?.state === 'on';\n const paused = states['binary_sensor.octoprint_paused']?.state === 'on';\n const health = Math.round((parseFloat(states['sensor.octoprint_serial_health_ratio']?.state) || 0) * 100);\n const prints = states['sensor.octoprint_printer_prints_today']?.state || '0';\n const ptime = states['sensor.octoprint_printer_print_time_today']?.state || '--';\n const fil = ((parseFloat(states['sensor.octoprint_filament_daily']?.state) || 0) / 10).toFixed(1);\n\n const row = (label, value, vc) => `\n \n ${label}\n ${value}\n
`;\n return `\n \n
\n \n Diagnostics\n
\n ${row('Connected', connected ? 'Yes' : 'No', connected ? '#4CAF50' : '#F44336')}\n ${row('Status', printing ? (paused ? 'Paused' : 'Printing') : 'Idle', printing ? '#4CAF50' : null)}\n ${row('Serial health', health + '%', health > 95 ? '#4CAF50' : health > 80 ? '#FF9800' : '#F44336')}\n ${row('Prints today', prints, null)}\n ${row('Time today', ptime + ' h', null)}\n ${row('Filament today', fil + ' m', null)}\n
\n `;\n ]]]"
+ },
+ "styles": {
+ "card": [
+ {
+ "background": "var(--ha-card-background, var(--card-background-color))"
+ },
+ {
+ "border-radius": "12px"
+ },
+ {
+ "padding": "0"
+ },
+ {
+ "height": "74px"
+ },
+ {
+ "position": "relative"
+ },
+ {
+ "box-shadow": "none"
+ },
+ {
+ "height": "190px"
+ }
+ ],
+ "custom_fields": {
+ "content": [
+ {
+ "position": "absolute"
+ },
+ {
+ "inset": "0"
+ },
+ {
+ "padding": "0"
+ }
+ ]
+ }
+ }
}
]
}
diff --git a/zigbee2mqtt/state.json b/zigbee2mqtt/state.json
index 96260e94..60b13dc7 100644
--- a/zigbee2mqtt/state.json
+++ b/zigbee2mqtt/state.json
@@ -4,7 +4,7 @@
"state": "ON",
"led_brightness": 100,
"countdown_to_turn_off": 0,
- "voltage": 122.4,
+ "voltage": 122,
"countdown_to_turn_on": 0,
"ac_frequency": 60,
"power_factor": 0.14,
@@ -15,21 +15,21 @@
"latest_source": "https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/images/ThirdReality/SmartPlug_Zigbee_PROD_OTA_V101_1.01.01.ota",
"latest_release_notes": null
},
- "power": 0.4,
+ "power": 0.5,
"linkquality": 116,
"current": 1.55,
"power_on_behavior": "on"
},
"0xffffb40e0607af27": {
"state": "ON",
- "voltage": 120.5,
+ "voltage": 119.8,
"ac_frequency": 60,
"led_brightness": 100,
"countdown_to_turn_off": 0,
"countdown_to_turn_on": 0,
- "power": 178,
- "current": 1.91,
- "energy": 31.89,
+ "power": 229.4,
+ "current": 1.94,
+ "energy": 31.91,
"power_factor": 0.98,
"update": {
"state": "idle",
@@ -45,7 +45,7 @@
"state": "ON",
"led_brightness": 100,
"countdown_to_turn_off": 0,
- "voltage": 121.9,
+ "voltage": 121.5,
"countdown_to_turn_on": 0,
"energy": 63.21,
"power_factor": 0.3,
@@ -77,10 +77,10 @@
"voltage": 120.8,
"state": "ON",
"ac_frequency": 60,
- "energy": 127.96,
- "power": 99.7,
+ "energy": 127.97,
+ "power": 97.9,
"current": 0.89,
- "power_factor": 0.93,
+ "power_factor": 0.94,
"update": {
"state": "idle",
"installed_version": 268513381,
@@ -95,13 +95,13 @@
"led_brightness": 100,
"countdown_to_turn_off": 0,
"countdown_to_turn_on": 0,
- "voltage": 120.7,
- "energy": 59.85,
+ "voltage": 121.1,
+ "energy": 59.86,
"state": "ON",
- "power": 48.7,
- "current": 0.65,
+ "power": 49.3,
+ "current": 0.49,
"ac_frequency": 60,
- "power_factor": 0.8,
+ "power_factor": 0.73,
"update": {
"state": "idle",
"installed_version": 268513381,
@@ -114,7 +114,7 @@
},
"0xffffb40e060895b3": {
"state": "ON",
- "voltage": 122,
+ "voltage": 121.8,
"ac_frequency": 60,
"energy": 8.78,
"current": 0.01,
@@ -136,11 +136,11 @@
"0xffffb40e0608864e": {
"led_brightness": 100,
"countdown_to_turn_off": 0,
- "voltage": 122.5,
+ "voltage": 122.6,
"energy": 19.46,
"countdown_to_turn_on": 0,
"state": "ON",
- "current": 0.04,
+ "current": 0.02,
"ac_frequency": 60,
"power": 0.3,
"power_factor": 0.18,
@@ -172,7 +172,7 @@
"0xffffb40e060893d8": {
"state": "ON",
"led_brightness": 100,
- "voltage": 122.7,
+ "voltage": 122.8,
"countdown_to_turn_off": 0,
"countdown_to_turn_on": 0,
"energy": 3.17,
@@ -187,7 +187,7 @@
"latest_source": "https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/images/ThirdReality/SmartPlug_Zigbee_PROD_OTA_V101_1.01.01.ota",
"latest_release_notes": null
},
- "power_factor": 0.06,
+ "power_factor": 0.12,
"power": 0.1
},
"0xa4c1380d0679ffff": {
@@ -245,7 +245,7 @@
},
"0xb40e060fffe717c5": {
"battery": 100,
- "occupancy": false,
+ "occupancy": true,
"tamper": false,
"battery_low": false,
"linkquality": 72,