7 Commits
Author SHA1 Message Date
gisle 204f372be2 fix mill
continuous-integration/drone/push Build is failing
2024-11-08 22:55:23 +01:00
gisle 083df1749b fix mill
continuous-integration/drone/push Build is failing
2024-11-08 21:34:35 +01:00
gisle 511ef97616 fix mill
continuous-integration/drone/push Build is failing
2024-11-08 21:26:28 +01:00
gisle 3d2b4e7bfe add mill driver 2024-11-08 21:08:24 +01:00
gisle c2f3d3c4d1 add non-opaque error on hue connect failed. 2024-10-06 16:19:04 +02:00
gisle 16c6d5316b add build
continuous-integration/drone/push Build is failing
2023-10-21 19:51:02 +02:00
gisle a558594537 fixes
continuous-integration/drone/push Build is failing
2023-10-21 19:48:58 +02:00
26 changed files with 68 additions and 325 deletions
+2
View File
@@ -7,6 +7,7 @@ import (
"git.aiterp.net/lucifer3/server/services/effectenforcer" "git.aiterp.net/lucifer3/server/services/effectenforcer"
"git.aiterp.net/lucifer3/server/services/httpapiv1" "git.aiterp.net/lucifer3/server/services/httpapiv1"
"git.aiterp.net/lucifer3/server/services/hue" "git.aiterp.net/lucifer3/server/services/hue"
"git.aiterp.net/lucifer3/server/services/mill"
"git.aiterp.net/lucifer3/server/services/mysqldb" "git.aiterp.net/lucifer3/server/services/mysqldb"
"git.aiterp.net/lucifer3/server/services/nanoleaf" "git.aiterp.net/lucifer3/server/services/nanoleaf"
"git.aiterp.net/lucifer3/server/services/script" "git.aiterp.net/lucifer3/server/services/script"
@@ -47,6 +48,7 @@ func main() {
bus.Join(nanoleaf.NewService()) bus.Join(nanoleaf.NewService())
bus.Join(hue.NewService()) bus.Join(hue.NewService())
bus.Join(tradfri.NewService()) bus.Join(tradfri.NewService())
bus.Join(mill.NewService())
bus.Join(uistate.NewService()) bus.Join(uistate.NewService())
bus.Join(script.NewService(resolver, variables)) bus.Join(script.NewService(resolver, variables))
bus.Join(database) bus.Join(database)
+2 -1
View File
@@ -7,4 +7,5 @@ node_modules
!.env.example !.env.example
vite.config.js.timestamp-* vite.config.js.timestamp-*
vite.config.ts.timestamp-* vite.config.ts.timestamp-*
/*.blend1 /*.blend1
/build
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
import{H as f,s as y,a8 as m,Z as q,a9 as w}from"./index.f09c780f.js";const o=[];function z(n,i){return{subscribe:A(n,i).subscribe}}function A(n,i=f){let u;const t=new Set;function a(e){if(y(n,e)&&(n=e,u)){const r=!o.length;for(const s of t)s[1](),o.push(s,n);if(r){for(let s=0;s<o.length;s+=2)o[s][0](o[s+1]);o.length=0}}}function l(e){a(e(n))}function b(e,r=f){const s=[e,r];return t.add(s),t.size===1&&(u=i(a)||f),e(n),()=>{t.delete(s),t.size===0&&(u(),u=null)}}return{set:a,update:l,subscribe:b}}function H(n,i,u){const t=!Array.isArray(n),a=t?[n]:n,l=i.length<2;return z(u,b=>{let e=!1;const r=[];let s=0,d=f;const g=()=>{if(s)return;d();const c=i(t?r[0]:r,b);l?b(c):d=w(c)?c:f},_=a.map((c,p)=>m(c,h=>{r[p]=h,s&=~(1<<p),e&&g()},()=>{s|=1<<p}));return e=!0,g(),function(){q(_),d()}})}export{H as d,A as w};
@@ -1 +0,0 @@
import{w as u}from"./index.faf1c53d.js";var _;const v=((_=globalThis.__sveltekit_1k9l1nc)==null?void 0:_.base)??"";var g;const k=((g=globalThis.__sveltekit_1k9l1nc)==null?void 0:g.assets)??v,m="1697835102898",R="sveltekit:snapshot",T="sveltekit:scroll",y="sveltekit:index",f={tap:1,hover:2,viewport:3,eager:4,off:-1};function I(e){let t=e.baseURI;if(!t){const n=e.getElementsByTagName("base");t=n.length?n[0].href:e.URL}return t}function S(){return{x:pageXOffset,y:pageYOffset}}function c(e,t){return e.getAttribute(`data-sveltekit-${t}`)}const d={...f,"":f.hover};function h(e){let t=e.assignedSlot??e.parentNode;return(t==null?void 0:t.nodeType)===11&&(t=t.host),t}function x(e,t){for(;e&&e!==t;){if(e.nodeName.toUpperCase()==="A"&&e.hasAttribute("href"))return e;e=h(e)}}function O(e,t){let n;try{n=new URL(e instanceof SVGAElement?e.href.baseVal:e.href,document.baseURI)}catch{}const o=e instanceof SVGAElement?e.target.baseVal:e.target,l=!n||!!o||E(n,t)||(e.getAttribute("rel")||"").split(/\s+/).includes("external"),r=(n==null?void 0:n.origin)===location.origin&&e.hasAttribute("download");return{url:n,external:l,target:o,download:r}}function U(e){let t=null,n=null,o=null,l=null,r=null,a=null,s=e;for(;s&&s!==document.documentElement;)o===null&&(o=c(s,"preload-code")),l===null&&(l=c(s,"preload-data")),t===null&&(t=c(s,"keepfocus")),n===null&&(n=c(s,"noscroll")),r===null&&(r=c(s,"reload")),a===null&&(a=c(s,"replacestate")),s=h(s);function i(b){switch(b){case"":case"true":return!0;case"off":case"false":return!1;default:return null}}return{preload_code:d[o??"off"],preload_data:d[l??"off"],keep_focus:i(t),noscroll:i(n),reload:i(r),replace_state:i(a)}}function p(e){const t=u(e);let n=!0;function o(){n=!0,t.update(a=>a)}function l(a){n=!1,t.set(a)}function r(a){let s;return t.subscribe(i=>{(s===void 0||n&&i!==s)&&a(s=i)})}return{notify:o,set:l,subscribe:r}}function w(){const{set:e,subscribe:t}=u(!1);let n;async function o(){clearTimeout(n);try{const l=await fetch(`${k}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!l.ok)return!1;const a=(await l.json()).version!==m;return a&&(e(!0),clearTimeout(n)),a}catch{return!1}}return{subscribe:t,check:o}}function E(e,t){return e.origin!==location.origin||!e.pathname.startsWith(t)}function L(e){e.client}const N={url:p({}),page:p({}),navigating:u(null),updated:w()};export{y as I,f as P,T as S,R as a,O as b,U as c,N as d,v as e,x as f,I as g,L as h,E as i,S as s};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
import{S as i,i as _,s as m,y as c,z as $,A as f,g as r,d as l,B as u,C as p,D as g,E as d,F as S}from"../chunks/index.f09c780f.js";import{S as x,a as h,M as C}from"../chunks/SelectContext.07ce997f.js";const b=!0,q=Object.freeze(Object.defineProperty({__proto__:null,prerender:b},Symbol.toStringTag,{value:"Module"}));function v(a){let t;const o=a[0].default,e=p(o,a,a[1],null);return{c(){e&&e.c()},l(n){e&&e.l(n)},m(n,s){e&&e.m(n,s),t=!0},p(n,s){e&&e.p&&(!t||s&2)&&g(e,o,n,n[1],t?S(o,n[1],s,null):d(n[1]),null)},i(n){t||(r(e,n),t=!0)},o(n){l(e,n),t=!1},d(n){e&&e.d(n)}}}function w(a){let t,o;return t=new C({props:{$$slots:{default:[v]},$$scope:{ctx:a}}}),{c(){c(t.$$.fragment)},l(e){$(t.$$.fragment,e)},m(e,n){f(t,e,n),o=!0},p(e,n){const s={};n&2&&(s.$$scope={dirty:n,ctx:e}),t.$set(s)},i(e){o||(r(t.$$.fragment,e),o=!0)},o(e){l(t.$$.fragment,e),o=!1},d(e){u(t,e)}}}function y(a){let t,o;return t=new h({props:{$$slots:{default:[w]},$$scope:{ctx:a}}}),{c(){c(t.$$.fragment)},l(e){$(t.$$.fragment,e)},m(e,n){f(t,e,n),o=!0},p(e,n){const s={};n&2&&(s.$$scope={dirty:n,ctx:e}),t.$set(s)},i(e){o||(r(t.$$.fragment,e),o=!0)},o(e){l(t.$$.fragment,e),o=!1},d(e){u(t,e)}}}function M(a){let t,o;return t=new x({props:{$$slots:{default:[y]},$$scope:{ctx:a}}}),{c(){c(t.$$.fragment)},l(e){$(t.$$.fragment,e)},m(e,n){f(t,e,n),o=!0},p(e,[n]){const s={};n&2&&(s.$$scope={dirty:n,ctx:e}),t.$set(s)},i(e){o||(r(t.$$.fragment,e),o=!0)},o(e){l(t.$$.fragment,e),o=!1},d(e){u(t,e)}}}function j(a,t,o){let{$$slots:e={},$$scope:n}=t;return a.$$set=s=>{"$$scope"in s&&o(1,n=s.$$scope)},[e,n]}class A extends i{constructor(t){super(),_(this,t,j,M,m,{})}}export{A as component,q as universal};
@@ -1 +0,0 @@
import{S,i as q,s as x,k as _,q as f,a as H,l as d,m as g,r as h,h as u,c as k,b as m,G as v,u as $,H as E,I as y}from"../chunks/index.f09c780f.js";import{d as C}from"../chunks/singletons.6d605789.js";const G=()=>{const s=C;return{page:{subscribe:s.page.subscribe},navigating:{subscribe:s.navigating.subscribe},updated:s.updated}},I={subscribe(s){return G().page.subscribe(s)}};function P(s){var b;let t,r=s[0].status+"",o,n,i,c=((b=s[0].error)==null?void 0:b.message)+"",l;return{c(){t=_("h1"),o=f(r),n=H(),i=_("p"),l=f(c)},l(e){t=d(e,"H1",{});var a=g(t);o=h(a,r),a.forEach(u),n=k(e),i=d(e,"P",{});var p=g(i);l=h(p,c),p.forEach(u)},m(e,a){m(e,t,a),v(t,o),m(e,n,a),m(e,i,a),v(i,l)},p(e,[a]){var p;a&1&&r!==(r=e[0].status+"")&&$(o,r),a&1&&c!==(c=((p=e[0].error)==null?void 0:p.message)+"")&&$(l,c)},i:E,o:E,d(e){e&&u(t),e&&u(n),e&&u(i)}}}function j(s,t,r){let o;return y(s,I,n=>r(0,o=n)),[o]}let A=class extends S{constructor(t){super(),q(this,t,j,P,x,{})}};export{A as component};
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
{"version":"1697835102898"}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

-68
View File
@@ -1,68 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="./favicon.png" />
<meta name="viewport" content="width=device-width" />
<meta name="darkreader" content="we've already gone dark" />
<style>
body, html {
background: #111114;
color: #ccc;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
</style>
<link href="./_app/immutable/assets/2.8d52c342.css" rel="stylesheet">
<link rel="modulepreload" href="./_app/immutable/entry/start.08a3b3b3.js">
<link rel="modulepreload" href="./_app/immutable/chunks/index.f09c780f.js">
<link rel="modulepreload" href="./_app/immutable/chunks/singletons.6d605789.js">
<link rel="modulepreload" href="./_app/immutable/chunks/index.faf1c53d.js">
<link rel="modulepreload" href="./_app/immutable/entry/app.16612d08.js">
<link rel="modulepreload" href="./_app/immutable/nodes/0.202e929e.js">
<link rel="modulepreload" href="./_app/immutable/chunks/SelectContext.07ce997f.js">
<link rel="modulepreload" href="./_app/immutable/nodes/2.2ea37eba.js">
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">
<div class="page svelte-170wh9b"></div>
<form novalidate></form>
<form novalidate></form>
<form novalidate></form>
<script>
{
__sveltekit_1k9l1nc = {
base: new URL(".", location).pathname.slice(0, -1),
env: {}
};
const element = document.currentScript.parentElement;
const data = [null,null];
Promise.all([
import("./_app/immutable/entry/start.08a3b3b3.js"),
import("./_app/immutable/entry/app.16612d08.js")
]).then(([kit, app]) => {
kit.start(app, element, {
node_ids: [0, 2],
data,
form: null,
error: null
});
});
}
</script>
</div>
</body>
</html>
Binary file not shown.
@@ -19,7 +19,7 @@
} }
let percentage: number let percentage: number
$: percentage = Math.max(Math.min((value || 0) * 100, 100), 0); $: percentage = Math.round(Math.max(Math.min((value || 0) * 100, 100), 0));
$: update(percentage); $: update(percentage);
</script> </script>
+29 -14
View File
@@ -1,6 +1,5 @@
<script lang="ts"> <script lang="ts">
import { runCommand } from "$lib/client/lucifer"; import { runCommand } from "$lib/client/lucifer";
import AssignmentState from "$lib/components/scripting/ScriptAssignmentState.svelte";
import Button from "$lib/components/Button.svelte"; import Button from "$lib/components/Button.svelte";
import Checkbox from "$lib/components/Checkbox.svelte"; import Checkbox from "$lib/components/Checkbox.svelte";
import type { DeviceIconName } from "$lib/components/DeviceIcon.svelte"; import type { DeviceIconName } from "$lib/components/DeviceIcon.svelte";
@@ -17,12 +16,11 @@
import { getStateContext } from "$lib/contexts/StateContext.svelte"; import { getStateContext } from "$lib/contexts/StateContext.svelte";
import { toEffectRaw, type EffectRaw, fromEffectRaw } from "$lib/models/assignment"; import { toEffectRaw, type EffectRaw, fromEffectRaw } from "$lib/models/assignment";
import type { DeviceEditOp } from "$lib/models/device"; import type { DeviceEditOp } from "$lib/models/device";
import { iconName } from "@fortawesome/free-solid-svg-icons/faQuestion";
import ScriptAssignmentState from "$lib/components/scripting/ScriptAssignmentState.svelte"; import ScriptAssignmentState from "$lib/components/scripting/ScriptAssignmentState.svelte";
const { modal } = getModalContext(); const { modal } = getModalContext();
const { selectedMasks, selectedMap, selectedList } = getSelectedContext(); const { selectedMasks, selectedMap, selectedList } = getSelectedContext();
const { deviceList, assignmentList } = getStateContext(); const { deviceList, state, assignmentList } = getStateContext();
let show: boolean = false; let show: boolean = false;
let match: string = ""; let match: string = "";
@@ -151,13 +149,28 @@
await runCommand({assign: { match, effect: fromEffectRaw(newEffect) }}); await runCommand({assign: { match, effect: fromEffectRaw(newEffect) }});
} }
if (enableRoom) { if (enableRoom) {
await runCommand({addAlias: { match, alias: `lucifer:room:${newRoom || customRoom}` }}); if (newRoom || customRoom) {
await runCommand({addAlias: { match, alias: `lucifer:room:${newRoom || customRoom}` }});
} else {
const group = $selectedList.flatMap(id => $state.devices[id].aliases).find(a => a.startsWith("lucifer:room:"));
if (group != null) {
await runCommand({removeAlias: { match, alias: group }});
}
}
enableRoom = false; enableRoom = false;
shouldWait = match.startsWith("lucifer:room:"); shouldWait = match.startsWith("lucifer:room:");
newRoom = newRoom || customRoom; newRoom = newRoom || customRoom;
} }
if (enableGroup && (newGroup || customGroup)) { if (enableGroup) {
await runCommand({addAlias: { match, alias: `lucifer:group:${newGroup || customGroup}` }}); if (newGroup || customGroup) {
await runCommand({addAlias: { match, alias: `lucifer:group:${newGroup || customGroup}` }});
} else {
const group = $selectedList.flatMap(id => $state.devices[id].aliases).find(a => a.startsWith("lucifer:group:"));
if (group != null) {
await runCommand({removeAlias: { match, alias: group }});
}
}
enableGroup = false; enableGroup = false;
shouldWait = match.startsWith("lucifer:group:"); shouldWait = match.startsWith("lucifer:group:");
newGroup = newGroup || customGroup; newGroup = newGroup || customGroup;
@@ -302,21 +315,23 @@
</HSplitPart> </HSplitPart>
</HSplit> </HSplit>
</ModalSection> </ModalSection>
<ModalSection bind:expanded={enableRename} title="Rename"> {#if $selectedList.length === 1}
<label for="name">New Name</label> <ModalSection bind:expanded={enableRename} title="Rename">
<input type="text" name="name" bind:value={newName} /> <label for="name">New Name</label>
</ModalSection> <input type="text" name="name" bind:value={newName} />
</ModalSection>
{/if}
<ModalSection bind:expanded={enableRoom} title="Change Room"> <ModalSection bind:expanded={enableRoom} title="Change Room">
<label for="newRoom">Select Room</label> <label for="newRoom">Select Room</label>
<select bind:value={newRoom}> <select bind:value={newRoom}>
{#each roomOptions as roomOption} {#each roomOptions as roomOption}
<option value={roomOption}>{roomOption}</option> <option value={roomOption}>{roomOption}</option>
{/each} {/each}
<option value="">Create Room</option> <option value="">Other Room / Clear</option>
</select> </select>
{#if newRoom == ""} {#if newRoom == ""}
<label for="customRoom">New Room</label> <label for="customRoom">New Room</label>
<input type="text" name="customRoom" bind:value={customRoom} /> <input type="text" name="customRoom" placeholder="Leave blank to clear room." bind:value={customRoom} />
{/if} {/if}
</ModalSection> </ModalSection>
<ModalSection bind:expanded={enableGroup} title="Change Group"> <ModalSection bind:expanded={enableGroup} title="Change Group">
@@ -325,11 +340,11 @@
{#each groupOptions as groupOption} {#each groupOptions as groupOption}
<option value={groupOption}>{groupOption}</option> <option value={groupOption}>{groupOption}</option>
{/each} {/each}
<option value="">Create Group</option> <option value="">Other Group / Clear</option>
</select> </select>
{#if newGroup == ""} {#if newGroup == ""}
<label for="customGroup">New Group</label> <label for="customGroup">New Group</label>
<input type="text" name="customGroup" bind:value={customGroup} /> <input type="text" name="customGroup" placeholder="Leave blank to clear group." bind:value={customGroup} />
{/if} {/if}
</ModalSection> </ModalSection>
<ModalSection bind:expanded={enableIcon} title="Change Icon"> <ModalSection bind:expanded={enableIcon} title="Change Icon">
+21 -18
View File
@@ -18,31 +18,34 @@ export type Effect =
| { gradient: { states: State[], animationMs: number, reverse: boolean, interpolate: boolean } } | { gradient: { states: State[], animationMs: number, reverse: boolean, interpolate: boolean } }
| { pattern: { states: State[], animationMs: number } } | { pattern: { states: State[], animationMs: number } }
| { random: { states: State[], animationMs: number, interpolate: boolean } } | { random: { states: State[], animationMs: number, interpolate: boolean } }
| { vrange: { states: State[], variable: string, min: number, max: number } } | { vrange: { states: State[], variable: string, min: number, max: number, interpolate: boolean } }
export function toEffectRaw(effect?: Effect): EffectRaw { export function toEffectRaw(effect?: Effect): EffectRaw {
let effectRaw: EffectRaw = { kind: "manual", states: [{color: null, intensity: null, power: null, temperature: null}], animationMs: 0, reverse: false, interpolate: false, min: 30, max: 300, variable: "motion.min", interleave: 0 };
if (effect != null) { if (effect != null) {
if ("manual" in effect) { if ("manual" in effect) {
return { kind: "solid", states: [effect.manual], animationMs: 0, reverse: false, interpolate: true, min: 30, max: 300, variable: "motion.min", interleave: 0 } effectRaw = { kind: "solid", states: [effect.manual], animationMs: 0, reverse: false, interpolate: true, min: 30, max: 300, variable: "motion.min", interleave: 0 }
} } else if ("solid" in effect) {
if ("solid" in effect) { effectRaw = { kind: "solid", ...effect.solid, min: 30, max: 300, variable: "motion.min", interpolate: true, reverse: false}
return { kind: "solid", ...effect.solid, min: 30, max: 300, variable: "motion.min", interpolate: true, reverse: false} } else if ("gradient" in effect) {
} effectRaw = { kind: "gradient", ...effect.gradient, min: 30, max: 300, variable: "motion.min", interleave: 0 }
if ("gradient" in effect) { } else if ("pattern" in effect) {
return { kind: "gradient", ...effect.gradient, min: 30, max: 300, variable: "motion.min", interleave: 0 } effectRaw = { kind: "pattern", ...effect.pattern, reverse: false, interpolate: true, min: 30, max: 300, variable: "motion.min", interleave: 0 }
} } else if ("random" in effect) {
if ("pattern" in effect) { effectRaw = { kind: "random", ...effect.random, reverse: false, min: 30, max: 300, variable: "motion.min", interleave: 0 }
return { kind: "pattern", ...effect.pattern, reverse: false, interpolate: true, min: 30, max: 300, variable: "motion.min", interleave: 0 } } else if ("vrange" in effect) {
} effectRaw = { kind: "vrange", ...effect.vrange, animationMs: 0, reverse: false, interleave: 0 }
if ("random" in effect) {
return { kind: "random", ...effect.random, reverse: false, min: 30, max: 300, variable: "motion.min", interleave: 0 }
}
if ("vrange" in effect) {
return { kind: "vrange", ...effect.vrange, animationMs: 0, interpolate: true, reverse: false, interleave: 0 }
} }
} }
return { kind: "manual", states: [{color: null, intensity: null, power: null, temperature: null}], animationMs: 0, reverse: false, interpolate: false, min: 30, max: 300, variable: "motion.min", interleave: 0 } effectRaw.states.forEach(state => {
if (state.intensity !== null) {
state.intensity = Math.floor(state.intensity * 100) / 100;
}
})
return effectRaw;
} }
export function fromEffectRaw(raw: EffectRaw): Effect { export function fromEffectRaw(raw: EffectRaw): Effect {
+3 -3
View File
@@ -143,12 +143,12 @@ export function toEditableScriptLine(line: ScriptLine): ScriptLineEditable {
not: line.if.condition.not || false, not: line.if.condition.not || false,
value: line.if.condition.value || "", value: line.if.condition.value || "",
}; };
base.then = line.if.then.map(toEditableScriptLine); base.then = (line.if.then||[]).map(toEditableScriptLine);
base.else = line.if.else.map(toEditableScriptLine); base.else = (line.if.else||[]).map(toEditableScriptLine);
} else if ("select" in line) { } else if ("select" in line) {
base.kind = "select"; base.kind = "select";
Object.assign(base, toMatchKindValue(line.select.match)); Object.assign(base, toMatchKindValue(line.select.match));
base.then = line.select.then.map(toEditableScriptLine); base.then = (line.select.then||[]).map(toEditableScriptLine);
} else if ("set" in line) { } else if ("set" in line) {
base.kind = "set"; base.kind = "set";
base.key = line.set.key base.key = line.set.key
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -348,7 +348,7 @@ func (b *Bridge) SetStates(patch map[string]device.State) {
func (b *Bridge) Run(ctx context.Context, bus *lucifer3.EventBus) interface{} { func (b *Bridge) Run(ctx context.Context, bus *lucifer3.EventBus) interface{} {
hwEvents, err := b.RefreshAll() hwEvents, err := b.RefreshAll()
if err != nil { if err != nil {
return errors.New("failed to connect to bridge") return fmt.Errorf("failed to connect to bridge: %s", err)
} }
bus.RunEvent(events.Log{ bus.RunEvent(events.Log{
+9 -8
View File
@@ -20,7 +20,8 @@ type WifiBridge struct {
ID string ID string
IP string IP string
state *device.State state *device.State
desiredState device.State
mx sync.Mutex mx sync.Mutex
started bool started bool
@@ -36,6 +37,8 @@ func (w *WifiBridge) SetState(id string, state device.State) bool {
return false return false
} }
w.desiredState = state
return true return true
} }
@@ -78,7 +81,7 @@ func (w *WifiBridge) refresh() error {
return err return err
} }
if w.state != nil { if w.state == nil {
w.state = &device.State{ w.state = &device.State{
Temperature: gentools.Ptr(temp), Temperature: gentools.Ptr(temp),
} }
@@ -93,14 +96,12 @@ func (w *WifiBridge) refresh() error {
}) })
} }
w.state.Temperature = gentools.Ptr(*w.state.Temperature - math.Mod(*w.state.Temperature, 0.5)) if w.desiredState.Temperature != nil && math.Abs(temp-*w.desiredState.Temperature) >= 0.1 {
if math.Abs(temp-*w.state.Temperature) >= 0.1 {
if err := w.writeTemperature(); err != nil { if err := w.writeTemperature(); err != nil {
return err return err
} }
} }
return nil return nil
} }
@@ -112,7 +113,7 @@ func (w *WifiBridge) getTemperature() (float64, error) {
req, err := http.NewRequest( req, err := http.NewRequest(
"GET", "GET",
"http://%s/set-temperature", fmt.Sprintf("http://%s/set-temperature", w.IP),
bytes.NewReader(body), bytes.NewReader(body),
) )
if err != nil { if err != nil {
@@ -144,7 +145,7 @@ func (w *WifiBridge) writeTemperature() error {
req, err := http.NewRequest( req, err := http.NewRequest(
"POST", "POST",
"http://%s/set-temperature", fmt.Sprintf("http://%s/set-temperature", w.IP),
bytes.NewReader(body), bytes.NewReader(body),
) )
if err != nil { if err != nil {