Skip to content
Draft
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
1,969 changes: 1,830 additions & 139 deletions custom_components/switch_manager/assets/switch_manager_panel.js

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion custom_components/switch_manager/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,8 @@ def __init__( self, hass: HomeAssistant, blueprint: Blueprint, _id, config ):
self._event_listeners = []
self._error = None
self.id = str( _id ) # Ensute id is a string for future proofing
self.name = config.get('name')
self.name = config.get('name')
self.custom_image = config.get('custom_image', '')
self.identifier = config.get('identifier')
self.blueprint: Blueprint
self.valid_blueprint: bool
Expand All @@ -545,6 +546,7 @@ def __init__( self, hass: HomeAssistant, blueprint: Blueprint, _id, config ):

def update( self, config ):
self.name = config.get('name')
self.custom_image = config.get('custom_image', '')
self.identifier = config.get('identifier')
self.variables: dict = config.get('variables')
self.rotate: int = config.get('rotate', 0)
Expand Down
1 change: 1 addition & 0 deletions custom_components/switch_manager/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def _normalize_config_action(value):
SWITCH_MANAGER_CONFIG_SCHEMA = vol.Schema({
vol.Required('id', default=None): vol.Any(str, int, None),
vol.Required('name'): cv.string,
vol.Required('custom_image', default=''): cv.string,
vol.Required('enabled', default=True): bool,
vol.Required('blueprint'): cv.string,
vol.Required('identifier'): cv.string,
Expand Down
1 change: 1 addition & 0 deletions custom_components/switch_manager/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
@attr.s
class SwitchManagerManagedSwitchData:
name = attr.ib(type=str, default='')
custom_image = attr.ib(type=str, default='')
enabled = attr.ib(type=bool, default=True)
blueprint = attr.ib(type=str, default=None)
identifier = attr.ib(type=str, default=None)
Expand Down
1 change: 1 addition & 0 deletions frontend/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export function createEmptyConfig(blueprint: Blueprint): SwitchConfig {
identifier: "",
blueprint: blueprint,
valid_blueprint: true,
custom_image: "",
buttons: [],
is_mismatch: false,
rotate: 0,
Expand Down
89 changes: 78 additions & 11 deletions frontend/src/switch-manager-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {
Route,
SwitchConfig,
SwitchListItem,
ConfigsResponse,
ConfigsResponse, SaveConfigResponse,
} from "./types";
import {
wsType,
Expand Down Expand Up @@ -36,6 +36,10 @@ const mdiContentCopy =
"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z";
const mdiMagnify =
"M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z";
const mdiCamera =
"M4,4H7L9,2H15L17,4H20A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20H4A2,2 0 0,1 2,18V6A2,2 0 0,1 4,4M12,7A5,5 0 0,0 7,12A5,5 0 0,0 12,17A5,5 0 0,0 17,12A5,5 0 0,0 12,7M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9Z"
const mdiImageFrage =
"M10,14.29L6.5,19H17.46L14.75,15.46L12.78,17.8L10,14.29M5,21V7H18.96V21H5M12,2.4L14.61,5.03H9.37L12,2.4M5,5.03C4.5,5.03 4,5.22 3.61,5.61C3.2,6 3,6.46 3,7V21C3,21.5 3.2,22 3.61,22.39C4,22.8 4.5,23 5,23H18.96C19.5,23 19.96,22.8 20.37,22.39C20.77,22 21,21.5 21,21V7C21,6.46 20.77,6 20.37,5.61C19.96,5.22 19.5,5.03 18.96,5.03H16L12,1L7.96,5.03H5Z"

@customElement("switch-manager-index")
export class SwitchManagerIndex extends LitElement {
Expand Down Expand Up @@ -113,6 +117,16 @@ export class SwitchManagerIndex extends LitElement {
item: SwitchListItem
): { path: string; label: string; action: () => void; warning?: boolean }[] {
return [
{
path: mdiCamera,
label: "Set custom Image",
action: () => this._uploadEncodedImage(item),
},
{
path: mdiImageFrage,
label: "Use Default Image",
action: () => this._removeCustomImage(item),
},
{
path: item.enabled ? mdiStop : mdiPlay,
label: item.enabled ? "Disable" : "Enable",
Expand Down Expand Up @@ -199,16 +213,9 @@ export class SwitchManagerIndex extends LitElement {
@click=${() => this._editSwitch(item.switch_id)}
>
<div class="td col-image">
${item.switch.valid_blueprint &&
item.switch.blueprint.has_image
? html`<img
src="${assetUrl(
item.blueprint_id + ".png"
)}"
/>`
: html`<ha-svg-icon
.path=${mdiGestureTapButton}
></ha-svg-icon>`}
${this._getImageSrcData(item)
? html`<img src="${this._getImageSrcData(item)}">`
: html`<ha-svg-icon .path=${mdiGestureTapButton}>`}
</div>
<div class="td col-name">
<span class="name-text">
Expand Down Expand Up @@ -296,6 +303,18 @@ export class SwitchManagerIndex extends LitElement {
navigate(navigateTo(`edit/${id}`));
}

private _getImageSrcData(item: SwitchListItem): string | null {
if(item.switch.custom_image !== "") {
return item.switch.custom_image
}

if(item.switch.valid_blueprint && item.switch.blueprint.has_image) {
return assetUrl(item.blueprint_id + ".png")
}

return null
}

private async _toggleEnabled(switchId: string, currentEnabled: boolean) {
try {
const res = await this.hass.callWS<{ enabled: boolean }>({
Expand All @@ -310,6 +329,54 @@ export class SwitchManagerIndex extends LitElement {
}
}

private async _uploadEncodedImage(item: SwitchListItem) {
try {
const imageInput = document.createElement("input");
imageInput.type = "file";

imageInput?.addEventListener("change", () => {
const file = imageInput.files?.[0];
if (!file) return;
showToast(this, `Selected file: ${file.name}`);

const reader = new FileReader();
reader.onload = async () => {
item.switch.custom_image = reader.result as string;

try {
await this.hass.callWS({
type: wsType("config/save"),
config: { ...item.switch, blueprint: (item.switch.blueprint as any).id },
fix_mismatch: true,
});
this._populateSwitches();
} catch (e: any) {
showToast(this, e.message);
}
};

reader.readAsDataURL(file);
});
imageInput.click();

} catch (e: any) {
showToast(this, e.message);
}
}

private async _removeCustomImage(item: SwitchListItem) {
try {
item.switch.custom_image = ""
await this.hass.callWS({
type: wsType("config/save"),
config: { ...item.switch, blueprint: (item.switch.blueprint as any).id },
fix_mismatch: true,
});
} catch (e: any) {
showToast(this, e.message);
}
}

private async _duplicate(switchId: string) {
try {
const res = await this.hass.callWS<{ config_id: string }>({
Expand Down
20 changes: 17 additions & 3 deletions frontend/src/switch-manager-switch-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,16 @@ export class SwitchManagerSwitchEditor extends LitElement {
</div>

<div class="view">
<div>
${this.config.custom_image === "" ? nothing : html`<img src="${this.config.custom_image}" id="custom-image">`}
${hasError ? nothing : html`<h3 id="blueprint-name">${this.blueprint?.service} / ${this.blueprint?.name}</h3>`}
</div>

<div id="switch-image" rotate="${this.config.rotate}">
${!this.blueprint || this.blueprint?.has_image
<div id="switch-image" rotate="${this.config.rotate}">
${!this.blueprint || this.blueprint?.has_image
? html`<svg id="switch-svg"></svg>`
: html`<ha-svg-icon .path=${mdiSwitchIcon}></ha-svg-icon>`}
</div>
</div>

${hasError ? nothing : html`
<switch-manager-button-actions
Expand Down Expand Up @@ -872,5 +875,16 @@ export class SwitchManagerSwitchEditor extends LitElement {
ha-fab.blocked {
bottom: calc(-80px - env(safe-area-inset-bottom));
}

#custom-image {
object-fit: cover;
float: left;
padding: 12px;
vertical-align: middle;
width: 80px;
height: 80px;
border-radius: 50%;
margin-right: 16px;
}
`;
}
1 change: 1 addition & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export interface SwitchConfig {
identifier: string;
blueprint: Blueprint;
valid_blueprint: boolean;
custom_image: string;
is_mismatch: boolean;
rotate: number;
buttons: SwitchConfigButton[];
Expand Down