From f00575fd7f71984d831423d8fa7b18f74cad512c Mon Sep 17 00:00:00 2001 From: Gisle Aune Date: Sun, 15 Oct 2023 21:23:11 +0200 Subject: [PATCH] fix hue, some ui tweaks. --- frontend/src/lib/components/DeviceIcon.svelte | 6 ++ frontend/src/lib/components/Icon.svelte | 2 + frontend/src/lib/components/Lamp.svelte | 4 +- .../bforms/BFormButtonOption.svelte | 8 ++ .../components/icons/generic_pendulum_01.svg | 17 ++++ .../lib/components/icons/hue_ensis_down.svg | 10 ++ .../src/lib/components/icons/hue_ensis_up.svg | 10 ++ .../components/scripting/ScriptLine.svelte | 12 +++ .../scripting/ScriptLineBlock.svelte | 23 ++++- frontend/src/lib/modals/TriggerModal.svelte | 2 +- services/hue/bridge.go | 99 +++++++++++-------- services/uistate/data.go | 2 +- 12 files changed, 149 insertions(+), 46 deletions(-) create mode 100644 frontend/src/lib/components/bforms/BFormButtonOption.svelte create mode 100644 frontend/src/lib/components/icons/generic_pendulum_01.svg create mode 100644 frontend/src/lib/components/icons/hue_ensis_down.svg create mode 100644 frontend/src/lib/components/icons/hue_ensis_up.svg diff --git a/frontend/src/lib/components/DeviceIcon.svelte b/frontend/src/lib/components/DeviceIcon.svelte index b519968..a0e6678 100644 --- a/frontend/src/lib/components/DeviceIcon.svelte +++ b/frontend/src/lib/components/DeviceIcon.svelte @@ -3,6 +3,7 @@ import generic_boob from "./icons/generic_boob.svg?raw"; import generic_ball from "./icons/generic_ball.svg?raw"; import generic_strip from "./icons/generic_strip.svg?raw"; + import generic_pendulum_01 from "./icons/generic_pendulum_01.svg?raw"; import hue_signe from "./icons/hue_signe.svg?raw"; import hue_dimmerswitch from "./icons/hue_dimmerswitch.svg?raw"; import hue_motionsensor from "./icons/hue_motionsensor.svg?raw"; @@ -15,6 +16,8 @@ import shape_square from "./icons/shape_square.svg?raw"; import shape_hexagon from "./icons/shape_hexagon.svg?raw"; import shape_triangle from "./icons/shape_triangle.svg?raw"; + import hue_ensis_up from "./icons/hue_ensis_up.svg?raw"; + import hue_ensis_down from "./icons/hue_ensis_down.svg?raw"; export const deviceIconMap = Object.seal({ generic_lamp, @@ -27,12 +30,15 @@ hue_lightbulb_e27, hue_lightbulb_e14, hue_lightbulb_gu10, + generic_pendulum_01, hue_adore_tube, hue_playbar, shape_square, shape_hexagon, shape_triangle, hue_go, + hue_ensis_up, + hue_ensis_down, }); export const deviceIconList = Object.seal(Object.keys(deviceIconMap).sort()) as DeviceIconName[]; diff --git a/frontend/src/lib/components/Icon.svelte b/frontend/src/lib/components/Icon.svelte index 2623abe..2fc77a2 100644 --- a/frontend/src/lib/components/Icon.svelte +++ b/frontend/src/lib/components/Icon.svelte @@ -42,6 +42,7 @@ import { faLightbulb } from "@fortawesome/free-solid-svg-icons/faLightbulb"; import { faChevronRight } from "@fortawesome/free-solid-svg-icons/faChevronRight"; import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown"; + import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp"; import { faTrash } from "@fortawesome/free-solid-svg-icons/faTrash"; import { faCheckToSlot } from "@fortawesome/free-solid-svg-icons/faCheckToSlot"; import { faEye } from "@fortawesome/free-solid-svg-icons/faEye"; @@ -83,6 +84,7 @@ "search": faSearch, "chevron_right": faChevronRight, "chevron_down": faChevronDown, + "chevron_up": faChevronUp, "trash": faTrash, "check_slot": faCheckToSlot, "eye": faEye, diff --git a/frontend/src/lib/components/Lamp.svelte b/frontend/src/lib/components/Lamp.svelte index 68c7b26..f66cc74 100644 --- a/frontend/src/lib/components/Lamp.svelte +++ b/frontend/src/lib/components/Lamp.svelte @@ -57,7 +57,7 @@ deviceTitle = device.hwState.internalName; } - if (hasColor && (!hasPower || device.desiredState.power)) { + if (hasColor && (!hasPower || device.desiredState?.power)) { iconColor = device.desiredColorRgb; } else { iconColor = null; @@ -70,7 +70,7 @@ if (sflags & SupportFlags.Temperature) { barColor = rgb(1.000,0.2,0.2); - barFraction = Math.min(1, Math.max(0, (device.desiredState.temperature||0) - 5) / 35) * 1; + barFraction = Math.min(1, Math.max(0, (device.desiredState?.temperature||0) - 5) / 35) * 1; } if (sflags & SupportFlags.Intensity) { diff --git a/frontend/src/lib/components/bforms/BFormButtonOption.svelte b/frontend/src/lib/components/bforms/BFormButtonOption.svelte new file mode 100644 index 0000000..e2a2b35 --- /dev/null +++ b/frontend/src/lib/components/bforms/BFormButtonOption.svelte @@ -0,0 +1,8 @@ + + + diff --git a/frontend/src/lib/components/icons/generic_pendulum_01.svg b/frontend/src/lib/components/icons/generic_pendulum_01.svg new file mode 100644 index 0000000..0a45512 --- /dev/null +++ b/frontend/src/lib/components/icons/generic_pendulum_01.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/frontend/src/lib/components/icons/hue_ensis_down.svg b/frontend/src/lib/components/icons/hue_ensis_down.svg new file mode 100644 index 0000000..b8c06bf --- /dev/null +++ b/frontend/src/lib/components/icons/hue_ensis_down.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/lib/components/icons/hue_ensis_up.svg b/frontend/src/lib/components/icons/hue_ensis_up.svg new file mode 100644 index 0000000..1b91a13 --- /dev/null +++ b/frontend/src/lib/components/icons/hue_ensis_up.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/lib/components/scripting/ScriptLine.svelte b/frontend/src/lib/components/scripting/ScriptLine.svelte index d3c3cbc..29934dc 100644 --- a/frontend/src/lib/components/scripting/ScriptLine.svelte +++ b/frontend/src/lib/components/scripting/ScriptLine.svelte @@ -11,7 +11,9 @@ import { BLANK_STATE, copyState } from "$lib/models/device"; import { toEditableScriptLine, type ScriptLineEditable } from "$lib/models/script"; + import { createEventDispatcher } from "svelte"; import type { IconName } from "../Icon.svelte"; + import BFormButtonOption from "../bforms/BFormButtonOption.svelte"; import BFormDeleteOption from "../bforms/BFormDeleteOption.svelte"; import BFormLine from "../bforms/BFormLine.svelte"; import BFormOption from "../bforms/BFormOption.svelte"; @@ -25,6 +27,10 @@ import ScriptSet from "./ScriptSet.svelte"; export let value: ScriptLineEditable; + export let first: boolean = false; + export let last: boolean = false; + + const dispatch = createEventDispatcher(); function deleteState(index: number) { value.effect.states = [ @@ -95,6 +101,12 @@ {/if} + {#if !first} + dispatch("up")} /> + {/if} + {#if !last} + dispatch("down")} /> + {/if} {#if value.kind === "assign"} diff --git a/frontend/src/lib/components/scripting/ScriptLineBlock.svelte b/frontend/src/lib/components/scripting/ScriptLineBlock.svelte index 0347829..31c08bd 100644 --- a/frontend/src/lib/components/scripting/ScriptLineBlock.svelte +++ b/frontend/src/lib/components/scripting/ScriptLineBlock.svelte @@ -7,6 +7,20 @@ export let value: ScriptLineEditable[]; export let add: boolean = false; + function moveUp(i: number) { + value = [...value]; + const temp = value[i]; + value[i] = value[i - 1]; + value[i - 1] = temp; + } + + function moveDown(i: number) { + value = [...value]; + const temp = value[i]; + value[i] = value[i + 1]; + value[i + 1] = temp; + } + function deleteLine(i: number) { value = [...value.slice(0, i), ...value.slice(i + 1)]; } @@ -14,6 +28,13 @@ {#each value as line, i} - deleteLine(i)} /> + moveUp(i)} + on:down={() => moveDown(i)} + on:delete={() => deleteLine(i)} + /> {/each} \ No newline at end of file diff --git a/frontend/src/lib/modals/TriggerModal.svelte b/frontend/src/lib/modals/TriggerModal.svelte index aeb90bb..90e92a7 100644 --- a/frontend/src/lib/modals/TriggerModal.svelte +++ b/frontend/src/lib/modals/TriggerModal.svelte @@ -55,7 +55,7 @@ if (id !== "") { current = toEditableTrigger($state.triggers[id]); } else { - current = newEditableTrigger($maskList[0], scriptList?.[0] || ""); + current = {...current, id: null}; } } diff --git a/services/hue/bridge.go b/services/hue/bridge.go index 05e3f8f..95b28cd 100644 --- a/services/hue/bridge.go +++ b/services/hue/bridge.go @@ -436,6 +436,8 @@ func (b *Bridge) Run(ctx context.Context, bus *lucifer3.EventBus) interface{} { } func (b *Bridge) makeCongruentLoop(ctx context.Context) { + hadFirst := make(map[string]bool, 16) + for range b.triggerCongruenceCheckCh { // I hate that I have to do this, but the SSE is not being reliable. _, _ = b.RefreshAll() @@ -473,52 +475,50 @@ func (b *Bridge) makeCongruentLoop(ctx context.Context) { update := ResourceUpdate{} // Handle power first - if desired.Power != nil && active.Power != nil && *desired.Power != *active.Power { + if desired.Power != nil && active.Power != nil && (!hadFirst[*lightID] || *desired.Power != *active.Power) { update.Power = gentools.Ptr(*desired.Power) updated = true } // Only do the rest if there's power. - if desired.Power == nil || *desired.Power { - if active.Color != nil && desired.Color != nil { - ac := *active.Color - dc := *desired.Color - - if !dc.IsKelvin() || !colorFlags[id].IsWarmWhite() { - dc, _ = dc.ToXY() - dc.XY = gentools.Ptr(light.Color.Gamut.Conform(*dc.XY)) - } + if active.Color != nil && desired.Color != nil { + ac := *active.Color + dc := *desired.Color - if dc.XY != nil { - if ac.K != nil { - ac.K = gentools.Ptr(1000000 / (1000000 / *ac.K)) - } + if !dc.IsKelvin() || !colorFlags[id].IsWarmWhite() { + dc, _ = dc.ToXY() + dc.XY = gentools.Ptr(light.Color.Gamut.Conform(*dc.XY)) + } - acXY, _ := ac.ToXY() - dist := dc.XY.DistanceTo(*acXY.XY) - if dist > 0.0002 { - update.ColorXY = gentools.Ptr(*dc.XY) - updated = true - } - } else { - dcMirek := 1000000 / *dc.K - if dcMirek < light.ColorTemperature.MirekSchema.MirekMinimum { - dcMirek = light.ColorTemperature.MirekSchema.MirekMinimum - } else if dcMirek > light.ColorTemperature.MirekSchema.MirekMaximum { - dcMirek = light.ColorTemperature.MirekSchema.MirekMaximum - } - acMirek := 0 - if ac.K != nil { - acMirek = 1000000 / *ac.K - } - if acMirek != dcMirek { - update.Mirek = &dcMirek - updated = true - } + if dc.XY != nil { + if ac.K != nil { + ac.K = gentools.Ptr(1000000 / (1000000 / *ac.K)) + } + + acXY, _ := ac.ToXY() + dist := dc.XY.DistanceTo(*acXY.XY) + if dist > 0.0002 || !hadFirst[*lightID] { + update.ColorXY = gentools.Ptr(*dc.XY) + updated = true + } + } else { + dcMirek := 1000000 / *dc.K + if dcMirek < light.ColorTemperature.MirekSchema.MirekMinimum { + dcMirek = light.ColorTemperature.MirekSchema.MirekMinimum + } else if dcMirek > light.ColorTemperature.MirekSchema.MirekMaximum { + dcMirek = light.ColorTemperature.MirekSchema.MirekMaximum + } + acMirek := 0 + if ac.K != nil { + acMirek = 1000000 / *ac.K + } + if acMirek != dcMirek || !hadFirst[*lightID] { + update.Mirek = &dcMirek + updated = true } } - if active.Intensity != nil && desired.Intensity != nil { + if active.Intensity != nil && desired.Intensity != nil || !hadFirst[*lightID] { if math.Abs(*active.Intensity-*desired.Intensity) >= 0.01 { update.Brightness = gentools.Ptr(*desired.Intensity * 100) updated = true @@ -529,11 +529,13 @@ func (b *Bridge) makeCongruentLoop(ctx context.Context) { if updated { update.TransitionDuration = gentools.Ptr(time.Millisecond * 101) updates["light/"+*lightID] = update + hadFirst[*lightID] = true } } if len(updates) > 0 { - timeout, cancel := context.WithTimeout(ctx, time.Millisecond*500*time.Duration(len(updates))) + timeout, cancel := context.WithTimeout(ctx, time.Second*60) + hadPower := false eg, ctx := errgroup.WithContext(timeout) for key := range updates { @@ -541,8 +543,19 @@ func (b *Bridge) makeCongruentLoop(ctx context.Context) { split := strings.SplitN(key, "/", 2) link := ResourceLink{Kind: split[0], ID: split[1]} + if update.Power != nil { + hadPower = true + } + eg.Go(func() error { - return b.client.UpdateResource(ctx, link, update) + if update.Power != nil { + return b.client.UpdateResource(ctx, link, ResourceUpdate{ + Power: update.Power, + TransitionDuration: update.TransitionDuration, + }) + } else { + return b.client.UpdateResource(ctx, link, update) + } }) } @@ -551,11 +564,15 @@ func (b *Bridge) makeCongruentLoop(ctx context.Context) { log.Println("Failed to run update", err) } - cancel() + if hadPower { + b.triggerCongruenceCheck() + } - // Wait the remaining time for the rate limit - <-rateLimit + cancel() } + + // Wait the remaining time for the rate limit + <-rateLimit } } diff --git a/services/uistate/data.go b/services/uistate/data.go index 8bc8b21..fa9b8d2 100644 --- a/services/uistate/data.go +++ b/services/uistate/data.go @@ -148,7 +148,7 @@ func (d *Data) ensureDevice(id string) Device { if device, ok := d.Devices[id]; ok { return device } else { - return Device{ID: id} + return Device{ID: id, Aliases: make([]string, 0)} } }