Skip to content
Merged
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
248 changes: 181 additions & 67 deletions src/components/widgets/mmu/MmuFilamentStatus.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,71 @@
/>
</g>

<g
id="sync-feedback-buffer-piston"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
style="stroke: var(--color-outline); fill: var(--color-outline)"
>
<rect
x="3"
y="0"
width="30"
height="40"
rx="3"
ry="3"
fill="none"
stroke-width="1.5"
/>
<path
d="M-15 -4 L-6 0 L-15 4 Z"
stroke-width="1"
fill-opacity="0.6"
/>
<path
d="M8 40 L 28 40"
stroke-width="4"
/>
<text
x="-22"
y="4"
font-size="11px"
text-anchor="end"
>
{{ syncFeedbackPistonText }}
</text>
Comment on lines +49 to +56
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

Vue template interpolation inside SVG defs may not work as expected. The text element with {{ syncFeedbackPistonText }} is defined in defs and referenced via use, which means the interpolation will only evaluate once during definition, not dynamically update when syncFeedbackPistonText changes. Consider moving the text element outside of defs and positioning it directly where needed, or use a different approach for dynamic text in reusable SVG elements.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think Copilot is mistaken (or it is with older Vue implementations) because I tested on Chrome, Safari, Firefox (on Mac) and Safari/Chrome on iPhone and it is reactive as expected(?)
I don't understand Vue well enough to know why, but I have validated it works as designed...

</g>

<g
id="sync-feedback-buffer-box"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
style="stroke: var(--color-outline)"
>
<rect
x="0"
y="0"
width="36"
height="45"
rx="3"
ry="3"
class="fil-background"
stroke-width="2"
fill-opacity="0.6"
/>
<path
d="M-3 10 0 10 M-3 22 0.5 22 M-3 34.5 0 34.5"
stroke-width="2"
stroke-opacity="0.6"
/>
<path
d="M8 0 L 28 0"
stroke-width="4"
/>
</g>

<g
id="sissors"
style="stroke: var(--color-outline); fill: none; stroke-linecap: round; stroke-linejoin: round;"
Expand Down Expand Up @@ -93,19 +158,19 @@
<g transform="matrix(23.2058 0 0 23.2058 329.7195 325.9517)">
<path
style="
stroke: rgb(0, 0, 0);
stroke-width: 0;
stroke-dasharray: none;
stroke-linecap: butt;
stroke-dashoffset: 0;
stroke-linejoin: miter;
stroke-miterlimit: 4;
is-custom-font: none;
font-file-url: none;
fill: rgb(254, 162, 54);
fill-rule: nonzero;
opacity: 1;
"
stroke: rgb(0, 0, 0);
stroke-width: 0;
stroke-dasharray: none;
stroke-linecap: butt;
stroke-dashoffset: 0;
stroke-linejoin: miter;
stroke-miterlimit: 4;
is-custom-font: none;
font-file-url: none;
fill: rgb(254, 162, 54);
fill-rule: nonzero;
opacity: 1;
"
vector-effect="non-scaling-stroke"
transform=" translate(-15.4288, -16.4198)"
stroke-linecap="round"
Expand Down Expand Up @@ -352,56 +417,75 @@
{{ temperatureText }}
</text>

<g v-if="hasSyncFeedback && filamentPos >= FILAMENT_POS_END_BOWDEN">
<transition name="fade">
<g
v-if="isSensorTriggered('filament_tension') && isSensorTriggered('filament_compression')"
key="neutral"
>
<text
x="288"
y="240"
>Neutral</text>
<use
xlink:href="#sync-feedback"
transform="translate(286, 247.5) scale(1.0,-1.0) rotate(90)"
/>
</g>
<g
v-else-if="isSensorTriggered('filament_tension')"
key="tension"
>
<text
x="288"
y="240"
>Tension</text>
<use
xlink:href="#sync-feedback"
transform="translate(258, 199) scale(1.2)"
/>
<use
xlink:href="#sync-feedback"
transform="translate(258, 271) scale(1.2,-1.2)"
/>
</g>
<g
v-else-if="isSensorTriggered('filament_compression')"
key="compression"
>
<text
x="288"
y="240"
>Compression</text>
<use
xlink:href="#sync-feedback"
transform="translate(258, 235) scale(1.2)"
/>
<use
xlink:href="#sync-feedback"
transform="translate(258, 235) scale(1.2,-1.2)"
/>
</g>
</transition>
<g v-if="hasSyncFeedback">
<use
xlink:href="#sync-feedback-buffer-piston"
:style="{
transform: `translate(232px, ${syncFeedbackPistonPos}px)`,
transition: 'transform 250ms ease',
}"
/>
<use
xlink:href="#sync-feedback-buffer-box"
transform="translate(232, 212)"
/>
<g v-if="syncFeedbackActive">
<transition name="fade">
<g
v-if="isSensorTriggered('filament_tension') && isSensorTriggered('filament_compression')"
key="neutral"
>
<text
x="298"
y="240"
>
Neutral
</text>
<use
xlink:href="#sync-feedback"
transform="translate(296, 247.5) scale(1.0,-1.0) rotate(90)"
/>
</g>
<g
v-else-if="isSensorTriggered('filament_tension')"
key="tension"
>
<text
x="298"
y="240"
>
Tension
</text>
<use
xlink:href="#sync-feedback"
transform="translate(272, 199) scale(1.2)"
/>
<use
xlink:href="#sync-feedback"
transform="translate(272, 271) scale(1.2,-1.2)"
/>
</g>
<g
v-else-if="isSensorTriggered('filament_compression')"
key="compression"
>
<text
x="298"
y="240"
>
Compression
</text>
<use
xlink:href="#sync-feedback"
transform="translate(272, 235) scale(1.2)"
/>
<use
xlink:href="#sync-feedback"
transform="translate(272, 235) scale(1.2,-1.2)"
/>
</g>
</transition>
</g>
</g>
<text
x="160"
Expand Down Expand Up @@ -565,7 +649,9 @@ export default class MmuFilamentStatus extends Mixins(StateMixin, MmuMixin) {
}

get encoderPosText (): string {
if (this.encoderPos < 10000) return `${this.encoderPos} mm`
if (this.encoderPos < 10000) {
return `${this.encoderPos} mm`
}
return `${this.encoderPos}`
}

Expand Down Expand Up @@ -624,9 +710,37 @@ export default class MmuFilamentStatus extends Mixins(StateMixin, MmuMixin) {
}

get hasSyncFeedback (): boolean {
return (
this.syncFeedbackEnabled && (this.hasSensor('filament_compression') || this.hasSensor('filament_tension'))
)
return this.hasFilamentCompressionSensor || this.hasFilamentTensionSensor || this.hasFilamentProportionalSensor
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The hasSyncFeedback getter no longer checks syncFeedbackEnabled, which was part of the original logic. This means the sync feedback buffer will always be displayed when any of the sensors exist, regardless of whether sync feedback is enabled. Consider whether syncFeedbackEnabled should still be part of this condition or if this change is intentional.

Suggested change
return this.hasFilamentCompressionSensor || this.hasFilamentTensionSensor || this.hasFilamentProportionalSensor
return this.syncFeedbackEnabled && (this.hasFilamentCompressionSensor || this.hasFilamentTensionSensor || this.hasFilamentProportionalSensor)

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

That is correct behavior because the sync-feedback "buffer" is also used as an endstop for homing the filament to the extruder. The actual enabled flag is simply whether dynamic rotation_distance adjustment is taking place and not about the existence of the sync feedback sensors.

}

get syncFeedbackActive (): boolean {
return this.hasSyncFeedback && this.filamentPos >= this.FILAMENT_POS_END_BOWDEN
}

get syncFeedbackPistonPos (): number {
const bias = this.syncFeedbackBiasModelled
const yPos = bias * 12 + 234
return yPos
}

get syncFeedbackPistonText (): string {
if (this.hasFilamentProportionalSensor) {
const bias = this.syncFeedbackBiasModelled
return bias.toFixed(2)
}
return ''
}

get hasFilamentProportionalSensor () {
return this.hasSensor('filament_proportional')
}

get hasFilamentCompressionSensor () {
return this.hasSensor('filament_compression')
}

get hasFilamentTensionSensor () {
return this.hasSensor('filament_tension')
}

get homedToEncoder (): boolean {
Expand Down
4 changes: 4 additions & 0 deletions src/mixins/mmu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,10 @@ export default class MmuMixin extends Vue {
return this.mmuState?.sync_feedback_enabled ?? false
}

get syncFeedbackBiasModelled (): number {
return this.mmuState?.sync_feedback_bias_modelled ?? 0
}

get clogDetectionEnabled (): boolean {
return this.mmuState?.clog_detection_enabled !== 0
}
Expand Down
1 change: 1 addition & 0 deletions src/typings/klipper.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ declare namespace Klipper {
sync_drive: boolean;
sync_feedback_state: string;
sync_feedback_enabled: boolean;
sync_feedback_bias_modelled: number;
clog_detection: number;
clog_detection_enabled: number;
endless_spool: number;
Expand Down