Skip to content

Commit

Permalink
feat: color support for useNewLight
Browse files Browse the repository at this point in the history
  • Loading branch information
TheNoim committed Dec 19, 2023
1 parent 78d1e45 commit 9854f19
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 169 deletions.
251 changes: 121 additions & 130 deletions deno.lock

Large diffs are not rendered by default.

128 changes: 95 additions & 33 deletions reactive_home/src/composeables/useNewLight.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import type { FullfilledUseState } from "./useState.ts";
import { useDebounceFn, reactive, watch, computed, extendRef } from "../dep.ts";
import {
useDebounceFn,
reactive,
watch,
computed,
extendRef,
brightBlue,
italic,
} from "../dep.ts";
import type { MessageBase, HassEntity } from "../dep.ts";
import { connection } from "../hass/connection.ts";
import { stringBoolToBool } from "../lib/util.ts";
import { formatTime } from "../lib/time.ts";

export function useNewLight(state: FullfilledUseState, debug = false) {
const skipContexts: string[] = [];
Expand All @@ -18,26 +27,47 @@ export function useNewLight(state: FullfilledUseState, debug = false) {
}

const updateHASSState = useDebounceFn(
async (newState: boolean, brightness: number) => {
async (
newState: boolean,
brightness?: number,
rgbColor?: [number, number, number]
) => {
const entity = state.value;

let service_data;

if ((brightness || rgbColor) && newState) {
service_data = {} as any;
if (brightness !== null && brightness !== undefined) {
service_data["brightness"] = brightness;
}
if (rgbColor !== null && rgbColor !== undefined) {
service_data["rgb_color"] = rgbColor;
}
} else {
service_data = {};
}

const payload = {
type: "call_service",
domain: entity.entity_id.split(".").at(0),
service: `turn_${newState ? "on" : "off"}`,
target: {
entity_id: entity.entity_id,
},
service_data:
newState && brightness > 0
? {
brightness: brightness,
}
: {},
service_data: service_data,
} satisfies MessageBase;

if (debug) {
console.log(`call_service(${entity.entity_id}): `, payload);
console.log(
`[${brightBlue("->")}][${formatTime(new Date())}] ${
entity.entity_id
}: ${italic(payload.service)} ${
typeof payload.service_data === "object"
? payload.service_data.brightness
: payload.service_data
}`
);
}

const result: { context: HassEntity["context"] } =
Expand All @@ -55,6 +85,7 @@ export function useNewLight(state: FullfilledUseState, debug = false) {
brightness: getBrightnessFromAttribute(state.value),
entity_id: state.value.entity_id,
lastChanged: new Date(state.value.last_changed),
rgbColor: state.value.attributes.rgb_color as [number, number, number],
});

const exposedValue = computed({
Expand All @@ -64,12 +95,12 @@ export function useNewLight(state: FullfilledUseState, debug = false) {
set(newValue) {
localValues.value = newValue;
localValues.lastChanged = new Date();
if (debug) {
console.log(
`call(${state.value.entity_id}): updateHASSState (via value change)`
);
}
updateHASSState(newValue, localValues.brightness);
// if (debug) {
// console.log(
// `call(${state.value.entity_id}): updateHASSState (via value change)`
// );
// }
updateHASSState(newValue, localValues.brightness, localValues.rgbColor);
},
});

Expand All @@ -78,14 +109,25 @@ export function useNewLight(state: FullfilledUseState, debug = false) {
return localValues.brightness;
},
set(newValue) {
if (newValue > 254) {
newValue = 254;
} else if (newValue < 0) {
newValue = 0;
}
newValue = Math.floor(newValue);
localValues.brightness = newValue;
localValues.lastChanged = new Date();
if (debug) {
console.log(
`call(${state.value.entity_id}): updateHASSState (via brightness change)`
);
if (newValue === 0 && localValues.value) {
localValues.value = false;
} else if (newValue > 0 && !localValues.value) {
localValues.value = true;
}
updateHASSState(localValues.value, newValue);
localValues.lastChanged = new Date();
// if (debug) {
// console.log(
// `call(${state.value.entity_id}): updateHASSState (via brightness change)`
// );
// }
updateHASSState(localValues.value, newValue, localValues.rgbColor);
},
});

Expand All @@ -98,26 +140,42 @@ export function useNewLight(state: FullfilledUseState, debug = false) {
},
});

const exposedRgbColor = computed({
get() {
return localValues.rgbColor;
},
set(newValue) {
localValues.rgbColor = newValue;
localValues.lastChanged = new Date();

updateHASSState(
localValues.value,
localValues.brightness,
localValues.rgbColor
);
},
});

// Incoming state changes from hass
watch(
() => state.value,
(newEntityState) => {
if (debug) {
console.log(
`incoming(${state.value.entity_id}): value=${stringBoolToBool(
newEntityState.state
)} brightness=${getBrightnessFromAttribute(
newEntityState
)} lastChanged=${new Date(newEntityState.last_changed)}`
);
// console.log(
// `incoming(${state.value.entity_id}): value=${stringBoolToBool(
// newEntityState.state
// )} brightness=${getBrightnessFromAttribute(
// newEntityState
// )} lastChanged=${new Date(newEntityState.last_changed)}`
// );
}

if (newEntityState.state === "unavailable") {
if (debug) {
console.log(
`incoming(${state.value.entity_id}): skip. New state is unavailable`
);
}
// if (debug) {
// console.log(
// `incoming(${state.value.entity_id}): skip. New state is unavailable`
// );
// }
return;
}

Expand All @@ -140,13 +198,17 @@ export function useNewLight(state: FullfilledUseState, debug = false) {
) {
localValues.brightness = getBrightnessFromAttribute(newEntityState);
}
if (localValues.rgbColor !== newEntityState.attributes.rgb_color) {
localValues.rgbColor = newEntityState.attributes.rgb_color;
}
}
);

const extendObject = {
brightness: exposedBrightness,
entity_id: state.value.entity_id,
lastChanged: exposedLastChanged,
rgbColor: exposedRgbColor,
};

return extendRef(exposedValue, extendObject);
Expand Down
40 changes: 36 additions & 4 deletions reactive_home/src/composeables/useState.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { connection } from "../hass/connection.ts";
import { getStates, HassEntities, entitiesColl } from "../dep.ts";
import { ref, computed } from "../dep.ts";
import { getStates, HassEntities, entitiesColl, watch } from "../dep.ts";
import { ref, computed, red, gray, deepEqual } from "../dep.ts";
import { formatTime } from "../lib/time.ts";

const collection = entitiesColl(connection);

Expand All @@ -14,12 +15,19 @@ export function useState(entity: string) {
return computed(() => currentStates.value?.[entity]);
}

export type UseAsyncStateOption = {
debug?: boolean;
};

/**
* Like useState, but it fetches the current state first
* @param entity entity_id
* @returns
*/
export async function useAsyncState(entity: string) {
export async function useAsyncState(
entity: string,
options: UseAsyncStateOption = {}
) {
const initialStates = await getStates(connection);

const initialState = initialStates.find(
Expand All @@ -30,9 +38,33 @@ export async function useAsyncState(entity: string) {
throw new Error("Failed to fetch initial state for entity " + entity);
}

return computed(() => {
const computedValue = computed(() => {
return currentStates.value ? currentStates.value[entity] : initialState;
});

if (options.debug) {
watch(
() => computedValue.value,
(newValue, oldValue) => {
if (!deepEqual(newValue, oldValue))
console.log(
`[${red("<-")}][${formatTime(new Date())}] ${entity}: ${gray(
`${oldValue.state}`
)}->${newValue.state} ${
"brightness" in newValue.attributes ||
"brightness" in oldValue.attributes
? `${gray(`${oldValue.attributes.brightness}` ?? "")}->${
newValue.attributes.brightness ?? ""
}`
: ""
}`
);
},
{ deep: true }
);
}

return computedValue;
}

export type FullfilledUseState = Awaited<ReturnType<typeof useAsyncState>>;
10 changes: 8 additions & 2 deletions reactive_home/src/dep.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import "./define-window.ts";

import colors from "https://esm.noim.io/[email protected]";

export * from "https://esm.noim.io/[email protected]";

export {
Expand All @@ -18,6 +20,10 @@ export type {
ComputedRef,
} from "https://esm.noim.io/@vue/[email protected]";

export * from "https://deno.land/[email protected]/fmt/colors.ts";

export * from "https://esm.noim.io/[email protected]";

export { useNow } from "./composeables/useNow.ts";

export {
Expand Down Expand Up @@ -48,6 +54,6 @@ import SunCalc from "https://esm.noim.io/[email protected]";

import parse from "https://esm.noim.io/[email protected]";

export { join } from "https://deno.land/std@0.208.0/path/mod.ts";
export { join } from "https://deno.land/std@0.209.0/path/mod.ts";

export { SunCalc, parse as parseDuration };
export { SunCalc, parse as parseDuration, colors };
7 changes: 7 additions & 0 deletions reactive_home/src/lib/time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function formatTime(date: Date) {
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");

return `${hours}:${minutes}:${seconds}`;
}
1 change: 1 addition & 0 deletions reactive_home/src/public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ export * from "./lib/light.ts";
export * from "./lib/sun.ts";
export * from "./lib/types.ts";
export * from "./lib/util.ts";
export { colors } from "./dep.ts";

export { connection } from "./hass/connection.ts";

0 comments on commit 9854f19

Please sign in to comment.