Skip to content

Commit

Permalink
readme
Browse files Browse the repository at this point in the history
  • Loading branch information
punxaphil committed Sep 12, 2023
1 parent 2f9a7ad commit e2124e9
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 34 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@ entities: # Entities are automatically discovered if you don't supply this setti
- media_player.sonos_hallway
- media_player.sonos_bedroom
- media_player.sonos_livingroom

volumeRatios: # If you want some speaker's volume to always be a certain percentage of another speaker's volume
- basePlayer: media_player.sonos_bedroom
adjustedPlayer: media_player.sonos_livingroom
ratio: 0.5

# groups specific
groupsTitle: ''
Expand All @@ -102,6 +105,13 @@ predefinedGroups: # defaults to empty
entities:
- media_player.matrum
- media_player.hall
- name: Kök&Hall
media: Legendary # If you want to start playing a specific favorite when grouping
entities: # Use below format if you want to set the volume of the speakers when grouping
- player: media_player.kok
volume: 10
- player: media_player.hall
volume: 5

# player specific
showVolumeUpAndDownButtons: true # default is false, shows buttons for increasing and decreasing volume
Expand Down
9 changes: 6 additions & 3 deletions src/editor/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ class Form extends BaseEditor {
}
}

export function computeLabel(schema: { name: string; help: string }) {
let unCamelCased = schema.name.replace(/([A-Z])/g, ' $1');
export function computeLabel({ help, label, name }: { name: string; help: string; label: string }) {
if (label) {
return label;
}
let unCamelCased = name.replace(/([A-Z])/g, ' $1');
unCamelCased = unCamelCased.charAt(0).toUpperCase() + unCamelCased.slice(1);
return unCamelCased + (schema.help ? ` (${schema.help})` : '');
return unCamelCased + (help ? ` (${help})` : '');
}

customElements.define('sonos-card-editor-form', Form);
69 changes: 61 additions & 8 deletions src/editor/predefined-group-editor.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,76 @@
import { html, TemplateResult } from 'lit';
import { ConfigPredefinedGroup } from '../types';
import { property } from 'lit/decorators.js';
import { mdiCheck, mdiDelete } from '@mdi/js';
import { BaseEditor } from './base-editor';
import { ConfigPredefinedGroup, ConfigPredefinedGroupPlayer, PredefinedGroup } from '../types';

class PredefinedGroupEditor extends BaseEditor {
@property() index!: number;
private predefinedGroup!: PredefinedGroup;

protected render(): TemplateResult {
this.config = this.store.config;
this.hass = this.store.hass;

const predefinedGroup: ConfigPredefinedGroup = this.config.predefinedGroups?.[this.index || 0] || {
this.predefinedGroup = this.store.predefinedGroups?.[this.index || 0] || {
name: '',
media: '',
entities: [],
};
const predefinedGroupWithoutVolumes: PredefinedGroup<string> = {
...this.predefinedGroup,
entities: this.predefinedGroup.entities.map((pgItem) => pgItem.player.id),
};
const schema = [
{
type: 'string',
name: 'name',
required: true,
},
{
type: 'string',
name: 'media',
},
{
name: 'entities',
selector: { entity: { multiple: true, filter: { integration: 'sonos', domain: 'media_player' } } },
},
];
return html`
Add/Edit Predefined Group
<h2>Add/Edit Predefined Group</h2>
<sonos-card-editor-form
.data=${predefinedGroup}
.data=${predefinedGroupWithoutVolumes}
.schema=${schema}
.store=${this.store}
.changed=${(ev: CustomEvent) => this.groupChanged(ev, this.index)}
></sonos-card-editor-form>
<div>
<h3>Volumes - will be set when players are grouped</h3>
${this.predefinedGroup.entities.map(({ player: { id, name }, volume }) => {
const schema = [
{
type: 'integer',
name: 'volume',
label: `${name}${volume ? `: ${volume}` : ''}`,
valueMin: 0,
valueMax: 100,
},
];
return html`
<sonos-card-editor-form
.data=${{ volume }}
.schema=${schema}
.store=${this.store}
.changed=${(ev: CustomEvent) => this.volumeChanged(ev, this.index, id)}
></sonos-card-editor-form>
`;
})}
</div>
<ha-control-button-group>
<ha-control-button @click="${this.dispatchClose}">
OK<ha-svg-icon .path=${mdiCheck} label="OK"></ha-svg-icon>
</ha-control-button>
${predefinedGroup.name
${this.predefinedGroup.name
? html`<ha-control-button
@click="${() => {
this.config.predefinedGroups = this.config.predefinedGroups?.filter((_, index) => index !== this.index);
Expand All @@ -55,19 +87,40 @@ class PredefinedGroupEditor extends BaseEditor {
}

private groupChanged(ev: CustomEvent, index: number): void {
const changed = ev.detail.value;
const changed: PredefinedGroup<string> = ev.detail.value;
const entities: ConfigPredefinedGroupPlayer[] = changed.entities.map((changedPlayerId) => {
const existing = this.predefinedGroup.entities.find(({ player: { id } }) => {
return id === changedPlayerId;
});
return existing ? { ...existing, player: existing.player.id } : { player: changedPlayerId };
});
const configItem: ConfigPredefinedGroup = {
...changed,
entities,
};
let groups = this.config.predefinedGroups;
if (!Array.isArray(groups)) {
groups = [];
}
if (groups[index]) {
groups[index] = changed;
groups[index] = configItem;
} else {
groups = [...groups, changed];
groups = [...groups, configItem];
}
this.config.predefinedGroups = groups;
this.configChanged();
}

private volumeChanged(ev: CustomEvent, index: number, playerId: string) {
const group = this.config.predefinedGroups?.[index];
if (group) {
const volume = ev.detail.value.volume;
group.entities = group.entities
.map((entity) => (typeof entity === 'string' ? { player: entity } : entity))
.map((entity) => (entity.player === playerId ? { ...entity, volume } : entity));
}
this.configChanged();
}
}

customElements.define('sonos-card-predefined-group-editor', PredefinedGroupEditor);
11 changes: 5 additions & 6 deletions src/model/media-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { CardConfig } from '../types';
import { getGroupPlayerIds } from '../utils/utils';

export class MediaPlayer {
id!: string;
name!: string;
state!: string;
id: string;
name: string;
state: string;
members: MediaPlayer[];
attributes!: {
attributes: {
[key: string]: any;
};
private readonly config: CardConfig;
Expand Down Expand Up @@ -44,8 +44,7 @@ export class MediaPlayer {
return (this.attributes.is_volume_muted as boolean) || this.members.some((member) => member.isMuted());
}
getCurrentTrack() {
const attributes = this.attributes;
return `${attributes.media_artist || ''} - ${attributes.media_title || ''}`.replace(/^ - /g, '');
return `${this.attributes.media_artist || ''} - ${this.attributes.media_title || ''}`.replace(/^ - /g, '');
}

private getEntityName(hassEntity: HassEntity, config: CardConfig) {
Expand Down
2 changes: 1 addition & 1 deletion src/model/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export default class Store {
pgEntityId = configItem;
} else {
volume = configItem.volume;
pgEntityId = configItem.id;
pgEntityId = configItem.player;
}
let result = undefined;
if (this.hass.states[pgEntityId]?.state !== 'unavailable') {
Expand Down
21 changes: 6 additions & 15 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export enum Section {
VOLUMES = 'volumes',
}

export type ConfigPredefinedGroupPlayer = PredefinedGroupPlayer<string>;
export type ConfigPredefinedGroup = PredefinedGroup<string | ConfigPredefinedGroupPlayer>;
export interface CardConfig extends LovelaceCardConfig {
sections?: Section[];
showVolumeUpAndDownButtons: boolean;
Expand Down Expand Up @@ -72,25 +74,14 @@ export interface MediaPlayerItem {
showFolderIcon?: boolean;
}

export interface ConfigPredefinedGroup {
export interface PredefinedGroup<T = PredefinedGroupPlayer> {
name: string;
entities: (string | ConfigPredefinedGroupPlayer)[];
entities: T[];
media?: string;
}

export interface ConfigPredefinedGroupPlayer {
id: string;
volume?: number;
}

export interface PredefinedGroup {
name: string;
entities: PredefinedGroupPlayer[];
media?: string;
}

export interface PredefinedGroupPlayer {
player: MediaPlayer;
export interface PredefinedGroupPlayer<T = MediaPlayer> {
player: T;
volume?: number;
}
export interface VolumeRatio {
Expand Down

0 comments on commit e2124e9

Please sign in to comment.