Skip to content

Commit 424e646

Browse files
authored
Update alexa range value attribute parameters (#2296)
Related to openhab/openhab-alexa#650. Related to openhab/openhab-alexa#651. Signed-off-by: jsetton <[email protected]>
1 parent 6ea38c3 commit 424e646

File tree

4 files changed

+45
-44
lines changed

4 files changed

+45
-44
lines changed

bundles/org.openhab.ui/web/src/assets/definitions/metadata/alexa/deviceattributes.js

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default {
4848
parameters: (itemType, item) => [
4949
p.inverted(itemType === 'Rollershutter'),
5050
p.presets(item.stateDescription, '20=Morning,60=Afternoon,80=Evening:@Setting.Night'),
51-
p.language(item.settings && item.settings.regional.language),
51+
p.language(item.settings?.regional?.language),
5252
p.actionMappings({ default: 'value' }, 'Close=0,Open=100,Lower=0,Raise=100', (config) => {
5353
const primaryControl = getGroupParameter('primaryControl', item.groups) || 'position'
5454
if (itemType === 'Dimmer') {
@@ -73,7 +73,7 @@ export default {
7373
parameters: (itemType, item) => [
7474
p.inverted(itemType === 'Rollershutter'),
7575
p.presets(item.stateDescription, '20=Morning,60=Afternoon,80=Evening:@Setting.Night'),
76-
p.language(item.settings && item.settings.regional.language),
76+
p.language(item.settings?.regional?.language),
7777
...(getGroupParameter('primaryControl', item.groups) !== 'tilt' ? [] : [
7878
p.actionMappings({ default: 'value' }, 'Close=0,Open=100', (config) => {
7979
if (itemType === 'Dimmer') {
@@ -107,7 +107,7 @@ export default {
107107
itemTypes: ['Number', 'String'],
108108
parameters: (itemType, item) => [
109109
p.supportedInputs(item.stateDescription, itemType === 'String' ? 'HDMI1=Cable,HDMI2=Kodi' : '1=Cable,2=Kodi'),
110-
p.language(item.settings && item.settings.regional.language),
110+
p.language(item.settings?.regional?.language),
111111
p.retrievable()
112112
]
113113
},
@@ -410,7 +410,7 @@ export default {
410410
p.retrievable(),
411411
p.supportedModes(item.stateDescription),
412412
p.ordered(),
413-
p.language(item.settings && item.settings.regional.language),
413+
p.language(item.settings?.regional?.language),
414414
p.actionMappings(
415415
{ set: 'mode', ...(config.ordered && { adjust: '(±deltaValue)' }) },
416416
'Close=Down,Open=Up,Lower=Down,Raise=Up'
@@ -421,7 +421,7 @@ export default {
421421
RangeValue: {
422422
itemTypes: ['Dimmer', 'Number', 'Number:*', 'Rollershutter'],
423423
supports: ['multiInstance'],
424-
parameters: (itemType, item) => [
424+
parameters: (itemType, item, config) => [
425425
p.capabilityNames(item.groups.length ? item.label : '@Setting.RangeValue', '@Setting.FanSpeed,Speed'),
426426
p.inverted(itemType === 'Rollershutter'),
427427
p.nonControllable(item.stateDescription),
@@ -432,12 +432,17 @@ export default {
432432
? [p.supportedCommands(['UP', 'DOWN', 'MOVE', 'STOP'], '[email protected],[email protected],[email protected]')]
433433
: []),
434434
p.supportedRange(
435-
item.stateDescription,
436-
itemType === 'Dimmer' || itemType === 'Rollershutter' ? '0:100:1' : '0:10:1'
435+
item,
436+
config,
437+
itemType === 'Dimmer' || itemType === 'Rollershutter'
438+
? '0:100:1'
439+
: config.nonControllable
440+
? '0:10:0.01'
441+
: '0:10:1'
437442
),
438443
p.presets(item.stateDescription, '[email protected]:Lowest,[email protected]:Highest'),
439444
p.unitOfMeasure(item),
440-
p.language(item.settings && item.settings.regional.language),
445+
p.language(item.settings?.regional?.language),
441446
p.actionMappings({ set: 'value', adjust: '(±deltaValue)' }, 'Close=0,Open=100,Lower=(-10),Raise=(+10)'),
442447
p.stateMappings({ default: 'value', range: 'minValue:maxValue' }, 'Closed=0,Open=1:100')
443448
]
@@ -452,7 +457,7 @@ export default {
452457
: [p.inverted()]),
453458
p.nonControllable(item.stateDescription),
454459
p.retrievable(),
455-
p.language(item.settings && item.settings.regional.language),
460+
p.language(item.settings?.regional?.language),
456461
p.actionMappings(['ON', 'OFF'], 'Close=OFF,Open=ON'),
457462
p.stateMappings(['ON', 'OFF'], 'Closed=OFF,Open=ON')
458463
]

bundles/org.openhab.ui/web/src/assets/definitions/metadata/alexa/devicetypes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const thermostatAttributes = [
6060

6161
const blindParameters = (_, item) => {
6262
const attributes = ['PositionState', 'TiltAngle']
63-
const metadata = item.members.map((mbr) => mbr.metadata && mbr.metadata.alexa.value).join(',')
63+
const metadata = item.members.map((mbr) => mbr.metadata?.alexa?.value).filter(Boolean).join(',')
6464
return attributes.every((attr) => metadata.includes(attr)) ? [p.primaryControl()] : []
6565
}
6666

bundles/org.openhab.ui/web/src/assets/definitions/metadata/alexa/helpers.js

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const docLink = (title, anchor) => {
1919
return `<a class="external text-color-blue" target="_blank" href="${link}">${title}</a>`
2020
}
2121

22-
export const getGroupParameter = (parameter, groups) => {
22+
export const getGroupParameter = (parameter, groups = []) => {
2323
for (const group of groups) {
2424
const config = group.metadata.alexa.config || {}
2525
if (parameter in config) return config[parameter]
@@ -39,25 +39,34 @@ export const getSemanticFormat = (type, format) =>
3939
''
4040
)
4141

42+
export const getSupportedRange = (item, config, defaultValue) => {
43+
const { minimum, maximum, step, pattern } = item.stateDescription || {}
44+
if (!isNaN(minimum) && !isNaN(maximum) && !isNaN(step)) return `${minimum}:${maximum}:${step}`
45+
const itemType = item.groupType || item.type
46+
if (itemType.startsWith('Number') && config.nonControllable) {
47+
const { precision, specifier } = pattern?.match(/%\d*(?:\.(?<precision>\d+))?(?<specifier>[df])/)?.groups || {}
48+
const [minimum, maximum] = defaultValue.split(':', 2)
49+
if (specifier === 'd') return `${minimum}:${maximum}:1`
50+
if (precision <= 16) return `${minimum}:${maximum}:${1 / 10 ** precision}`
51+
}
52+
return defaultValue
53+
}
54+
4255
export const getTemperatureScale = (item) => {
4356
const itemType = item.groupType || item.type
44-
const unitSymbol = item.unitSymbol
45-
const statePresentation = (item.stateDescription && item.stateDescription.pattern) || ''
46-
const format = (itemType === 'Number:Temperature' && unitSymbol) || statePresentation
47-
if (format.endsWith('°C')) return 'CELSIUS'
48-
if (format.endsWith('°F')) return 'FAHRENHEIT'
49-
const { measurementSystem } = (item.settings && item.settings.regional) || {}
57+
const format = (itemType === 'Number:Temperature' && item.unitSymbol) || item.stateDescription?.pattern
58+
if (format?.endsWith('°C')) return 'CELSIUS'
59+
if (format?.endsWith('°F')) return 'FAHRENHEIT'
60+
const measurementSystem = item.settings?.regional?.measurementSystem
5061
if (measurementSystem === 'SI') return 'CELSIUS'
5162
if (measurementSystem === 'US') return 'FAHRENHEIT'
5263
}
5364

5465
export const getUnitOfMeasure = (item) => {
5566
const itemType = item.groupType || item.type
56-
const unitSymbol = item.unitSymbol
57-
const statePresentation = (item.stateDescription && item.stateDescription.pattern) || ''
5867
const format =
5968
((itemType === 'Dimmer' || itemType === 'Rollershutter') && '%') ||
60-
(itemType.startsWith('Number:') && unitSymbol) ||
61-
statePresentation
62-
return Object.keys(UNITS_OF_MEASURE).find((id) => format.endsWith(UNITS_OF_MEASURE[id]))
69+
(itemType.startsWith('Number:') && item.unitSymbol) ||
70+
item.stateDescription?.pattern
71+
return Object.keys(UNITS_OF_MEASURE).find((id) => format?.endsWith(UNITS_OF_MEASURE[id]))
6372
}

bundles/org.openhab.ui/web/src/assets/definitions/metadata/alexa/parameters.js

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
getGroupParameter,
1414
getOptions,
1515
getSemanticFormat,
16+
getSupportedRange,
1617
getTemperatureScale,
1718
getUnitOfMeasure,
1819
titleCase
@@ -202,7 +203,7 @@ export default {
202203
name: 'nonControllable',
203204
label: 'Non-Controllable',
204205
type: 'BOOLEAN',
205-
default: (stateDescription && stateDescription.readOnly) === true,
206+
default: stateDescription?.readOnly === true,
206207
visible: (_, config) => !!config.retrievable
207208
}),
208209
ordered: () => ({
@@ -229,14 +230,12 @@ export default {
229230
` (${docLink('Asset Catalog')})`,
230231
type: 'TEXT',
231232
default:
232-
stateDescription &&
233-
stateDescription.options &&
234-
stateDescription.options
235-
.filter((option) => !isNaN(option.value))
233+
stateDescription?.options?.filter((option) => !isNaN(option.value))
236234
.map((option) => `${option.value}=${option.label}`)
237235
.slice(0, STATE_DESCRIPTION_OPTIONS_LIMIT),
238236
placeholder: placeholder.replace(/,/g, '\n'),
239-
multiple: true
237+
multiple: true,
238+
visible: (_, config) => !config.nonControllable
240239
}),
241240
primaryControl: () => ({
242241
name: 'primaryControl',
@@ -356,10 +355,7 @@ export default {
356355
description: 'Each input formatted as <code>inputValue=inputName1:inputName2:...</code>',
357356
type: 'TEXT',
358357
default:
359-
stateDescription &&
360-
stateDescription.options &&
361-
stateDescription.options
362-
.map((option) => `${option.value}=${option.label}`)
358+
stateDescription?.options?.map((option) => `${option.value}=${option.label}`)
363359
.slice(0, STATE_DESCRIPTION_OPTIONS_LIMIT),
364360
placeholder: placeholder.replace(/,/g, '\n'),
365361
multiple: true,
@@ -372,10 +368,7 @@ export default {
372368
`Each mode formatted as <code>mode=@assetIdOrName1:@assetIdOrName2:...</code> (${docLink('Asset Catalog')})`,
373369
type: 'TEXT',
374370
default:
375-
stateDescription &&
376-
stateDescription.options &&
377-
stateDescription.options
378-
.map((option) => `${option.value}=${option.label}`)
371+
stateDescription?.options?.map((option) => `${option.value}=${option.label}`)
379372
.slice(0, STATE_DESCRIPTION_OPTIONS_LIMIT),
380373
placeholder: 'Normal=Normal:Cottons\nWhites=Whites',
381374
multiple: true,
@@ -391,18 +384,12 @@ export default {
391384
multiple: true,
392385
advanced: true
393386
}),
394-
supportedRange: (stateDescription, defaultValue) => ({
387+
supportedRange: (item, config, defaultValue) => ({
395388
name: 'supportedRange',
396389
label: 'Supported Range',
397390
description: 'Formatted as <code>minValue:maxValue:precision</code>',
398391
type: 'TEXT',
399-
default:
400-
stateDescription &&
401-
!isNaN(stateDescription.minimum) &&
402-
!isNaN(stateDescription.maximum) &&
403-
!isNaN(stateDescription.step)
404-
? `${stateDescription.minimum}:${stateDescription.maximum}:${stateDescription.step}`
405-
: defaultValue,
392+
default: getSupportedRange(item, config, defaultValue),
406393
pattern: '[+-]?[0-9]+:[+-]?[0-9]+:[0-9]+'
407394
}),
408395
supportedThermostatModes: () => ({

0 commit comments

Comments
 (0)