mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-21 18:47:13 +02:00
feat(smart-plugs): auto-off after AMS drying completes (#1349)
Reporter Kyobinoyo asked for the equivalent of the existing print-finish auto-off but triggered when AMS drying ends. Two new SmartPlug columns: auto_off_after_drying (default false), off_delay_after_drying_minutes (default 10 — AMS chamber is hot post-cycle so longer cooldown than the print-finish default of 5). SQLite + Postgres migrations both idempotent. Trigger lives in BambuMQTTClient — per-AMS _previous_dry_times tracks the dry_time > 0 → 0 falling edge and fires a new on_drying_complete(ams_id) callback. Plumbed through PrinterManager.set_drying_complete_callback to SmartPlugManager.on_drying_complete(printer_id, db), which walks linked plugs and respects the per-plug toggle. Catches queue, ambient and manual drying identically because it observes firmware state, not scheduler intent. Frontend: single "Auto Off After Drying" toggle + delay input on the smart plug card, next to the existing print-finish auto-off section. Per-AMS plug routing (separate plug for AMS only, per-AMS targeting on dual-AMS printers) deferred — Bambuddy's plug model is plug→printer, so the trigger fires whenever any AMS on the linked printer finishes a cycle.
This commit is contained in:
@@ -1447,6 +1447,9 @@ export interface SmartPlug {
|
||||
off_delay_mode: 'time' | 'temperature';
|
||||
off_delay_minutes: number;
|
||||
off_temp_threshold: number;
|
||||
// #1349: auto-off after AMS drying completes.
|
||||
auto_off_after_drying: boolean;
|
||||
off_delay_after_drying_minutes: number;
|
||||
username: string | null;
|
||||
password: string | null;
|
||||
// Power alerts
|
||||
@@ -1518,6 +1521,9 @@ export interface SmartPlugCreate {
|
||||
off_delay_mode?: 'time' | 'temperature';
|
||||
off_delay_minutes?: number;
|
||||
off_temp_threshold?: number;
|
||||
// #1349
|
||||
auto_off_after_drying?: boolean;
|
||||
off_delay_after_drying_minutes?: number;
|
||||
username?: string | null;
|
||||
password?: string | null;
|
||||
// Power alerts
|
||||
@@ -1581,6 +1587,9 @@ export interface SmartPlugUpdate {
|
||||
off_delay_mode?: 'time' | 'temperature';
|
||||
off_delay_minutes?: number;
|
||||
off_temp_threshold?: number;
|
||||
// #1349
|
||||
auto_off_after_drying?: boolean;
|
||||
off_delay_after_drying_minutes?: number;
|
||||
username?: string | null;
|
||||
password?: string | null;
|
||||
// Power alerts
|
||||
|
||||
@@ -209,6 +209,7 @@ export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{/* Feature Badges */}
|
||||
{(plug.power_alert_enabled || plug.schedule_enabled || plug.plug_type === 'mqtt') && (
|
||||
<div className="flex flex-wrap gap-1.5 mb-3">
|
||||
@@ -448,6 +449,42 @@ export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Auto Off After Drying (#1349) — independent of the
|
||||
print-finish auto-off above. Uses its own delay because
|
||||
the AMS chamber is hot post-cycle and users often want
|
||||
more cooldown than the print-finish default. Fires when
|
||||
any AMS attached to the linked printer finishes a dry
|
||||
cycle. */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-white">{t('smartPlugs.autoOffAfterDrying')}</p>
|
||||
<p className="text-xs text-bambu-gray">{t('smartPlugs.autoOffAfterDryingDescription')}</p>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={plug.auto_off_after_drying}
|
||||
onChange={(e) => updateMutation.mutate({ auto_off_after_drying: e.target.checked })}
|
||||
className="sr-only peer"
|
||||
/>
|
||||
<div className="w-9 h-5 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-bambu-green"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{plug.auto_off_after_drying && (
|
||||
<div className="pl-4 border-l-2 border-bambu-dark-tertiary">
|
||||
<label className="block text-xs text-bambu-gray mb-1">{t('smartPlugs.delayAfterDryingMinutes')}</label>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="120"
|
||||
value={plug.off_delay_after_drying_minutes}
|
||||
onChange={(e) => updateMutation.mutate({ off_delay_after_drying_minutes: parseInt(e.target.value) || 10 })}
|
||||
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:border-bambu-green focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
@@ -4462,6 +4462,9 @@ export default {
|
||||
autoOffDescription: 'Ausschalten wenn Druck abgeschlossen (einmalig)',
|
||||
autoOffPersistent: 'Aktiviert lassen',
|
||||
autoOffPersistentDescription: 'Zwischen Drucken aktiviert bleiben statt einmalig',
|
||||
autoOffAfterDrying: 'Automatisch aus nach Trocknung',
|
||||
autoOffAfterDryingDescription: 'Ausschalten, wenn AMS-Trocknung abgeschlossen ist',
|
||||
delayAfterDryingMinutes: 'Verzögerung nach Trocknung (Minuten)',
|
||||
turnOffDelayMode: 'Ausschaltverzögerungsmodus',
|
||||
time: 'Zeit',
|
||||
temp: 'Temp.',
|
||||
|
||||
@@ -4471,6 +4471,9 @@ export default {
|
||||
autoOffDescription: 'Turn off when print completes (one-shot)',
|
||||
autoOffPersistent: 'Keep Enabled',
|
||||
autoOffPersistentDescription: 'Stay enabled between prints instead of one-shot',
|
||||
autoOffAfterDrying: 'Auto Off After Drying',
|
||||
autoOffAfterDryingDescription: 'Turn off when AMS drying completes',
|
||||
delayAfterDryingMinutes: 'Drying delay (minutes)',
|
||||
turnOffDelayMode: 'Turn Off Delay Mode',
|
||||
time: 'Time',
|
||||
temp: 'Temp',
|
||||
|
||||
@@ -4452,6 +4452,9 @@ export default {
|
||||
autoOffDescription: 'Éteindre à la fin de l\'impression (unique)',
|
||||
autoOffPersistent: 'Garder activé',
|
||||
autoOffPersistentDescription: 'Rester activé entre les impressions au lieu d\'une seule fois',
|
||||
autoOffAfterDrying: 'Arrêt auto après séchage',
|
||||
autoOffAfterDryingDescription: 'Éteindre à la fin du séchage de l\'AMS',
|
||||
delayAfterDryingMinutes: 'Délai après séchage (minutes)',
|
||||
turnOffDelayMode: 'Mode de délai d\'extinction',
|
||||
time: 'Temps',
|
||||
temp: 'Temp.',
|
||||
|
||||
@@ -4451,6 +4451,9 @@ export default {
|
||||
autoOffDescription: 'Spegni quando la stampa è completata (una tantum)',
|
||||
autoOffPersistent: 'Mantieni attivo',
|
||||
autoOffPersistentDescription: 'Resta attivo tra le stampe invece di una tantum',
|
||||
autoOffAfterDrying: 'Spegni dopo asciugatura',
|
||||
autoOffAfterDryingDescription: 'Spegni al termine dell\'asciugatura AMS',
|
||||
delayAfterDryingMinutes: 'Ritardo dopo asciugatura (minuti)',
|
||||
turnOffDelayMode: 'Modalità ritardo spegnimento',
|
||||
time: 'Tempo',
|
||||
temp: 'Temp.',
|
||||
|
||||
@@ -4463,6 +4463,9 @@ export default {
|
||||
autoOffDescription: '印刷完了時にオフにする(ワンショット)',
|
||||
autoOffPersistent: '有効のまま維持',
|
||||
autoOffPersistentDescription: 'ワンショットではなく印刷間で有効のまま維持',
|
||||
autoOffAfterDrying: '乾燥完了後に自動オフ',
|
||||
autoOffAfterDryingDescription: 'AMSの乾燥が完了したらオフにする',
|
||||
delayAfterDryingMinutes: '乾燥後の遅延(分)',
|
||||
turnOffDelayMode: 'オフ遅延モード',
|
||||
time: '時間',
|
||||
temp: '温度',
|
||||
|
||||
@@ -4451,6 +4451,9 @@ export default {
|
||||
autoOffDescription: 'Desligar quando a impressão terminar (única vez)',
|
||||
autoOffPersistent: 'Manter ativado',
|
||||
autoOffPersistentDescription: 'Permanecer ativado entre impressões em vez de única vez',
|
||||
autoOffAfterDrying: 'Desligar Após Secagem',
|
||||
autoOffAfterDryingDescription: 'Desligar quando a secagem do AMS terminar',
|
||||
delayAfterDryingMinutes: 'Atraso após secagem (minutos)',
|
||||
turnOffDelayMode: 'Modo de atraso para desligar',
|
||||
time: 'Tempo',
|
||||
temp: 'Temp.',
|
||||
|
||||
@@ -4451,6 +4451,9 @@ export default {
|
||||
autoOffDescription: '打印完成时关闭(一次性)',
|
||||
autoOffPersistent: '保持启用',
|
||||
autoOffPersistentDescription: '在打印之间保持启用而非一次性',
|
||||
autoOffAfterDrying: '干燥完成后自动关闭',
|
||||
autoOffAfterDryingDescription: 'AMS 干燥完成后关闭',
|
||||
delayAfterDryingMinutes: '干燥后延迟(分钟)',
|
||||
turnOffDelayMode: '关闭延迟模式',
|
||||
time: '时间',
|
||||
temp: '温度',
|
||||
|
||||
@@ -4451,6 +4451,9 @@ export default {
|
||||
autoOffDescription: '列印完成時關閉(一次性)',
|
||||
autoOffPersistent: '保持啟用',
|
||||
autoOffPersistentDescription: '在列印之間保持啟用而非一次性',
|
||||
autoOffAfterDrying: '乾燥完成後自動關閉',
|
||||
autoOffAfterDryingDescription: 'AMS 乾燥完成後關閉',
|
||||
delayAfterDryingMinutes: '乾燥後延遲(分鐘)',
|
||||
turnOffDelayMode: '關閉延遲模式',
|
||||
time: '時間',
|
||||
temp: '溫度',
|
||||
|
||||
Reference in New Issue
Block a user