Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat blinking light action #145

Closed
wants to merge 19 commits into from
Closed
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
17 changes: 16 additions & 1 deletion front/src/config/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,20 @@
"label": "Wähle die Lichter aus, die umgeschaltet werden sollen",
"description": "Diese Aktion schaltet das Licht ein, wenn es ausgeschaltet ist bzw. schaltet es aus, wenn es eingeschaltet ist"
},
"blinkLights": {
"label": "Wählen Sie die Lichter aus, die Sie zum Blinken bringen möchten",
"description": "Stellen Sie die Dauer und die Geschwindigkeit des Blinkens ein",
"blinkingTime": {
"label": "Dauer (in Sekunden)",
"placeholder": "3"
},
"blinkingSpeed": {
"label": "Modus",
"slow": "Langsam",
"medium": "Mittel",
"fast": "Schnell"
}
},
"turnOnSwitches": {
"label": "Wähle die Schalter aus, die eingeschaltet werden sollen"
},
Expand Down Expand Up @@ -1816,7 +1830,8 @@
"light": {
"turn-on": "Licht einschalten",
"turn-off": "Licht ausschalten",
"toggle": "Lichter umschalten"
"toggle": "Lichter umschalten",
"blink": "Lichter blinken lassen"
},
"switch": {
"turn-on": "Schalter einschalten",
Expand Down
17 changes: 16 additions & 1 deletion front/src/config/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1677,6 +1677,20 @@
"label": "Select the lights you want to toggle",
"description": "This action turn on the light if state is off or turn off the light if state is on"
},
"blinkLights": {
"label": "Select the lights you want to make blink",
"description": "Configure blinking duration and speed",
"blinkingTime": {
"label": "Duration (in seconds)",
"placeholder": "3"
},
"blinkingSpeed": {
"label": "Mode",
"slow": "Slow",
"medium": "Medium",
"fast": "Fast"
}
},
"turnOnSwitches": {
"label": "Select the switches you want to turn on"
},
Expand Down Expand Up @@ -1818,7 +1832,8 @@
"light": {
"turn-on": "Turn On the Lights",
"turn-off": "Turn Off the Lights",
"toggle": "Toggle the Lights"
"toggle": "Toggle the Lights",
"blink": "Make the Lights blink"
},
"switch": {
"turn-on": "Turn On the Switches",
Expand Down
19 changes: 17 additions & 2 deletions front/src/config/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1679,6 +1679,20 @@
"label": "Sélectionnez les lumières que vous souhaitez inverser",
"description": "Cette action allume la lumière si éteinte, sinon éteins la lumière"
},
"blinkLights": {
"label": "Sélectionnez les lumières que vous souhaitez faire clignoter",
"description": "Réglez la durée et la vitesse de clignotement",
"blinkingTime": {
"label": "Durée (en secondes)",
"placeholder": "3"
},
"blinkingSpeed": {
"label": "Mode",
"slow": "Lent",
"medium": "Normal",
"fast": "Rapide"
}
},
"turnOnSwitches": {
"label": "Sélectionnez les prises que vous souhaitez allumer"
},
Expand Down Expand Up @@ -1818,9 +1832,10 @@
},
"delay": "Attendre",
"light": {
"turn-on": "Allumer la lumière",
"turn-on": "Allumer les lumières",
"turn-off": "Eteindre les lumières",
"toggle": "Inverser les lumières"
"toggle": "Inverser les lumières",
"blink": "Faire clignoter les lumières"
},
"switch": {
"turn-on": "Allumer les prises",
Expand Down
13 changes: 12 additions & 1 deletion front/src/routes/scene/edit-scene/ActionCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import DeviceSetValue from './actions/DeviceSetValue';
import SendMessageParams from './actions/SendMessageParams';
import OnlyContinueIfParams from './actions/only-continue-if/OnlyContinueIfParams';
import TurnOnOffLightParams from './actions/TurnOnOffLightParams';
import BlinkLightParams from './actions/BlinkLightParams';
import TurnOnOffSwitchParams from './actions/TurnOnOffSwitchParams';
import StartSceneParams from './actions/StartSceneParams';
import UserPresence from './actions/UserPresence';
Expand All @@ -38,6 +39,7 @@ const ACTION_ICON = {
[ACTIONS.LIGHT.TURN_ON]: 'fe fe-toggle-right',
[ACTIONS.LIGHT.TURN_OFF]: 'fe fe-toggle-left',
[ACTIONS.LIGHT.TOGGLE]: 'fe fe-shuffle',
[ACTIONS.LIGHT.BLINK]: 'fe fe-star',
[ACTIONS.SWITCH.TURN_ON]: 'fe fe-toggle-right',
[ACTIONS.SWITCH.TURN_OFF]: 'fe fe-toggle-left',
[ACTIONS.SWITCH.TOGGLE]: 'fe fe-shuffle',
Expand Down Expand Up @@ -97,7 +99,8 @@ const ActionCard = ({ children, ...props }) => {
'col-lg-6':
props.action.type === ACTIONS.MESSAGE.SEND ||
props.action.type === ACTIONS.CALENDAR.IS_EVENT_RUNNING ||
props.action.type === ACTIONS.MQTT.SEND,
props.action.type === ACTIONS.MQTT.SEND ||
props.action.type === ACTIONS.LIGHT.BLINK,
'col-lg-4':
props.action.type !== ACTIONS.CONDITION.ONLY_CONTINUE_IF &&
props.action.type !== ACTIONS.MESSAGE.SEND &&
Expand Down Expand Up @@ -173,6 +176,14 @@ const ActionCard = ({ children, ...props }) => {
updateActionProperty={props.updateActionProperty}
/>
)}
{props.action.type === ACTIONS.LIGHT.BLINK && (
<BlinkLightParams
action={props.action}
columnIndex={props.columnIndex}
index={props.index}
updateActionProperty={props.updateActionProperty}
/>
)}
{props.action.type === ACTIONS.SWITCH.TURN_ON && (
<TurnOnOffSwitchParams
action={props.action}
Expand Down
130 changes: 130 additions & 0 deletions front/src/routes/scene/edit-scene/actions/BlinkLightParams.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { Component } from 'preact';
import { connect } from 'unistore/preact';
import { Text, Localizer } from 'preact-i18n';
import Select from 'react-select';

class BlinkLight extends Component {
getOptions = async () => {
try {
const devices = await this.props.httpClient.get('/api/v1/device', {
device_feature_category: 'light',
device_feature_type: 'binary'
});
const deviceOptions = devices.map(device => ({
value: device.selector,
label: device.name
}));
await this.setState({ deviceOptions });
this.refreshSelectedOptions(this.props);
return deviceOptions;
} catch (e) {
console.error(e);
}
};
handleChange = selectedOptions => {
if (selectedOptions) {
const lights = selectedOptions.map(selectedOption => selectedOption.value);
this.props.updateActionProperty(this.props.columnIndex, this.props.index, 'devices', lights);
} else {
this.props.updateActionProperty(this.props.columnIndex, this.props.index, 'devices', []);
}
};
handleChangeBlinkingTime = e => {
let newValue = Number.isInteger(parseInt(e.target.value, 10)) ? parseInt(e.target.value, 10) : 0;
this.props.updateActionProperty(this.props.columnIndex, this.props.index, 'blinking_time', newValue);
};
handleChangeBlinkingSpeed = e => {
this.props.updateActionProperty(this.props.columnIndex, this.props.index, 'blinking_speed', e.target.value);
};
refreshSelectedOptions = nextProps => {
const selectedOptions = [];
if (nextProps.action.devices && this.state.deviceOptions) {
nextProps.action.devices.forEach(light => {
const deviceOption = this.state.deviceOptions.find(deviceOption => deviceOption.value === light);
if (deviceOption) {
selectedOptions.push(deviceOption);
}
});
}
this.setState({ selectedOptions });
};
constructor(props) {
super(props);
this.state = {
deviceOptions: null,
selectedOptions: []
};
}
async componentDidMount() {
this.getOptions();
}

componentWillReceiveProps(nextProps) {
this.refreshSelectedOptions(nextProps);
}

render(props, { selectedOptions, deviceOptions }) {
return (
<div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<div class="form-label">
<Text id="editScene.actionsCard.blinkLigths.label" />
</div>
<Select
defaultValue={[]}
isMulti
value={selectedOptions}
onChange={this.handleChange}
options={deviceOptions}
/>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<div class="form-label">
<Text id="editScene.actionsCard.blinkLights.blinkingTime.label" />
</div>
<Localizer>
<input
type="text"
class="form-control"
value={props.action.blinking_time}
onChange={this.handleChangeBlinkingTime}
placeholder={<Text id="editScene.actionsCard.blinkLights.blinkingTime.placeholder" />}
/>
</Localizer>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<div class="form-label">
<Text id="editScene.actionsCard.blinkLights.blinkingSpeed.label" />
</div>
<select
class="custom-select"
value={props.action.blinking_speed}
onChange={this.handleChangeBlinkingSpeed}
>
<option value="slow">
<Text id="editScene.actionsCard.blinkLights.blinkingSpeed.slow" />
</option>
<option value="medium">
<Text id="editScene.actionsCard.blinkLights.blinkingSpeed.medium" />
</option>
<option value="fast">
<Text id="editScene.actionsCard.blinkLights.blinkingSpeed.fast" />
</option>
</select>
</div>
</div>
</div>
</div>
);
}
}

export default connect('httpClient', {})(BlinkLight);
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const ACTION_LIST = [
ACTIONS.LIGHT.TURN_ON,
ACTIONS.LIGHT.TURN_OFF,
ACTIONS.LIGHT.TOGGLE,
ACTIONS.LIGHT.BLINK,
ACTIONS.SWITCH.TURN_ON,
ACTIONS.SWITCH.TURN_OFF,
ACTIONS.SWITCH.TOGGLE,
Expand Down
42 changes: 42 additions & 0 deletions server/lib/scene/scene.actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,48 @@ const actionsFunc = {
}
});
},
[ACTIONS.LIGHT.BLINK]: async (self, action, scope) => {
const blinkingSpeed = action.blinking_speed;
const blinkingTime = action.blinking_time * 1000 + 1;
let blinkingInterval;
switch (blinkingSpeed) {
case 'slow':
blinkingInterval = 1000;
break;
case 'medium':
blinkingInterval = 500;
break;
case 'fast':
blinkingInterval = 200;
break;
default:
blinkingInterval = 200;
break;
}
await Promise.map(action.devices, async (deviceSelector) => {
try {
const device = self.stateManager.get('device', deviceSelector);
const deviceFeature = getDeviceFeature(
device,
DEVICE_FEATURE_CATEGORIES.LIGHT,
DEVICE_FEATURE_TYPES.LIGHT.BINARY,
);
const oldValue = deviceFeature.last_value;
let newValue = 0;
/* eslint-disable no-await-in-loop */
// We want this loops to be sequential
for (let i = 0; i < blinkingTime; i += blinkingInterval) {
newValue = 1 - newValue;
await self.device.setValue(device, deviceFeature, newValue);
await new Promise((resolve) => setTimeout(resolve, blinkingInterval));
}
/* eslint-enable no-await-in-loop */
await self.device.setValue(device, deviceFeature, oldValue);
} catch (e) {
logger.warn(e);
}
});
},
[ACTIONS.SWITCH.TURN_ON]: async (self, action, scope) => {
await Promise.map(action.devices, async (deviceSelector) => {
try {
Expand Down
2 changes: 2 additions & 0 deletions server/models/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ const actionSchema = Joi.array().items(
alarm_mode: Joi.string().valid(...ALARM_MODES_LIST),
topic: Joi.string(),
message: Joi.string().allow(''),
blinking_time: Joi.number(),
blinking_speed: Joi.string().valid('slow', 'medium', 'fast'),
}),
),
);
Expand Down
Loading
Loading