Implemented frontend for motion trigger settings
Still read-only
This commit is contained in:
parent
0b42c49210
commit
9c22414fea
33
devserver.js
33
devserver.js
@ -162,6 +162,39 @@ app.post('/api/triggers/time', function(req, res)
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var motionTriggers = {
|
||||||
|
enabled: true,
|
||||||
|
enabledDuringTimeTrigger: false,
|
||||||
|
transitionTime: 1000,
|
||||||
|
delay: 30000,
|
||||||
|
triggers: [
|
||||||
|
{
|
||||||
|
pin: 14,
|
||||||
|
brightness: 64,
|
||||||
|
direction: 2,
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pin: 15,
|
||||||
|
brightness: 64,
|
||||||
|
direction: 3,
|
||||||
|
enabled: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
app.get('/api/triggers/motion', function(req, res)
|
||||||
|
{
|
||||||
|
res.send(motionTriggers);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/triggers/motion', function(req, res)
|
||||||
|
{
|
||||||
|
res.sendStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
app.listen(3000, function()
|
app.listen(3000, function()
|
||||||
{
|
{
|
||||||
console.log('Development server listening on port 3000')
|
console.log('Development server listening on port 3000')
|
||||||
|
46
web/app.js
46
web/app.js
@ -44,7 +44,15 @@ function startApp()
|
|||||||
triggers: {
|
triggers: {
|
||||||
time: {
|
time: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
transitionTime: 0,
|
transitionTime: null,
|
||||||
|
triggers: []
|
||||||
|
},
|
||||||
|
|
||||||
|
motion: {
|
||||||
|
enabled: false,
|
||||||
|
enabledDuringTimeTrigger: false,
|
||||||
|
transitionTime: null,
|
||||||
|
delay: null,
|
||||||
triggers: []
|
triggers: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -124,6 +132,8 @@ function startApp()
|
|||||||
self.loadSystem().then(function()
|
self.loadSystem().then(function()
|
||||||
{
|
{
|
||||||
self.loadTimeTriggers().then(function()
|
self.loadTimeTriggers().then(function()
|
||||||
|
{
|
||||||
|
self.loadMotionTriggers().then(function()
|
||||||
{
|
{
|
||||||
self.loadSteps().then(function()
|
self.loadSteps().then(function()
|
||||||
{
|
{
|
||||||
@ -134,6 +144,7 @@ function startApp()
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@ -230,6 +241,20 @@ function startApp()
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
loadMotionTriggers: function()
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
return axios.get('/api/triggers/motion')
|
||||||
|
.then(function(response)
|
||||||
|
{
|
||||||
|
if (typeof response.data == 'object')
|
||||||
|
self.triggers.motion = response.data;
|
||||||
|
})
|
||||||
|
.catch(function(error)
|
||||||
|
{
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
loadSteps: function()
|
loadSteps: function()
|
||||||
{
|
{
|
||||||
@ -558,6 +583,8 @@ function startApp()
|
|||||||
|
|
||||||
self.saving = true;
|
self.saving = true;
|
||||||
|
|
||||||
|
// TODO motion triggers (or separate the forms?)
|
||||||
|
|
||||||
var timeSettings = {
|
var timeSettings = {
|
||||||
enabled: self.triggers.time.enabled,
|
enabled: self.triggers.time.enabled,
|
||||||
transitionTime: self.triggers.time.transitionTime,
|
transitionTime: self.triggers.time.transitionTime,
|
||||||
@ -624,6 +651,23 @@ function startApp()
|
|||||||
self.triggers.time.triggers.splice(index, 1);
|
self.triggers.time.triggers.splice(index, 1);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addMotionTrigger: function()
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
self.triggers.motion.triggers.push({
|
||||||
|
brightness: 0,
|
||||||
|
enabled: true,
|
||||||
|
pin: 2,
|
||||||
|
direction: 0
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteMotionTrigger: function(index)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
self.triggers.motion.triggers.splice(index, 1);
|
||||||
|
},
|
||||||
|
|
||||||
getDisplayTime: function(time, isRelative)
|
getDisplayTime: function(time, isRelative)
|
||||||
{
|
{
|
||||||
var result = '';
|
var result = '';
|
||||||
|
2
web/dist/bundle.css
vendored
2
web/dist/bundle.css
vendored
File diff suppressed because one or more lines are too long
2
web/dist/bundle.js
vendored
2
web/dist/bundle.js
vendored
File diff suppressed because one or more lines are too long
@ -84,16 +84,23 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<h3>{{ $t('triggers.timeTitle') }}</h3>
|
<h3>{{ $t('triggers.timeTitle') }}</h3>
|
||||||
|
|
||||||
|
<input type="checkbox" id="timeEnabled" v-model.boolean="triggers.time.enabled"><label for="timeEnabled" class="label-inline">{{ $t('triggers.timeEnabled') }}</label>
|
||||||
|
|
||||||
|
<div v-if="triggers.time.enabled">
|
||||||
<div class="warning" v-if="!wifiStatus.station.enabled || wifiStatus.station.status != 3">
|
<div class="warning" v-if="!wifiStatus.station.enabled || wifiStatus.station.status != 3">
|
||||||
{{ $t('triggers.timeInternet') }}
|
{{ $t('triggers.timeInternet') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="triggers.time.triggers.length" class="timeTriggers">
|
<label for="timeTransitionTime">{{ $t('triggers.timeTransitionTime') }}</label>
|
||||||
|
<input type="number" id="timeTransitionTime" v-model.number="triggers.time.transitionTime">
|
||||||
|
|
||||||
|
<label>Regels</label>
|
||||||
|
<div v-if="triggers.time.triggers.length">
|
||||||
<div v-for="(trigger, index) in triggers.time.triggers" class="panel">
|
<div v-for="(trigger, index) in triggers.time.triggers" class="panel">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<input type="checkbox" :id="'time' + index + '_enabled'" v-model.boolean="trigger.enabled"><label class="label-inline" :for="'time' + index + '_enabled'">{{ $t('triggers.timeEnabled') }}</label>
|
<input type="checkbox" :id="'time' + index + '_enabled'" v-model.boolean="trigger.enabled"><label class="label-inline" :for="'time' + index + '_enabled'">{{ $t('triggers.timeTriggerEnabled') }}</label>
|
||||||
<span class="actions">
|
<span class="actions">
|
||||||
[ <a href="#" @click.prevent="deleteItemTrigger(index)">{{ $t('triggers.timeDelete') }}</a> ]
|
[ <a href="#" @click.prevent="deleteTimeTrigger(index)">{{ $t('triggers.timeDelete') }}</a> ]
|
||||||
</span>
|
</span>
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -165,13 +172,66 @@
|
|||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button class="button-primary button-outline" :disabled="saving" @click.prevent="addTimeTrigger">{{ $t('triggers.timeAdd') }}</button>
|
<button class="button-primary button-outline" :disabled="saving" @click.prevent="addTimeTrigger">{{ $t('triggers.timeAdd') }}</button>
|
||||||
<input class="button-primary" type="submit" :disabled="saving" :value="saving ? $t('applyButtonSaving') : $t('applyButton')">
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<h3>{{ $t('triggers.motionTitle') }}</h3>
|
<h3>{{ $t('triggers.motionTitle') }}</h3>
|
||||||
|
|
||||||
|
<input type="checkbox" id="motionEnabled" v-model.boolean="triggers.motion.enabled"><label for="motionEnabled" class="label-inline">{{ $t('triggers.motionEnabled') }}</label>
|
||||||
|
|
||||||
|
<div v-if="triggers.motion.enabled">
|
||||||
|
<input type="checkbox" id="motionEnabledDuringTimeTrigger" v-model.boolean="triggers.motion.enabledDuringTimeTrigger"><label for="motionEnabledDuringTimeTrigger" class="label-inline">{{ $t('triggers.motionEnabledDuringTimeTrigger') }}</label>
|
||||||
|
|
||||||
|
<label for="motionTransitionTime">{{ $t('triggers.motionTransitionTime') }}</label>
|
||||||
|
<input type="number" id="motionTransitionTime" v-model.number="triggers.motion.transitionTime">
|
||||||
|
|
||||||
|
<label>Regels</label>
|
||||||
|
<div v-if="triggers.motion.triggers.length">
|
||||||
|
<div v-for="(trigger, index) in triggers.motion.triggers" class="panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<input type="checkbox" :id="'motion' + index + '_enabled'" v-model.boolean="trigger.enabled"><label class="label-inline" :for="'motion' + index + '_enabled'">{{ $t('triggers.motionTriggerEnabled') }}</label>
|
||||||
|
<span class="actions">
|
||||||
|
[ <a href="#" @click.prevent="deleteMotionTrigger(index)">{{ $t('triggers.motionDelete') }}</a> ]
|
||||||
|
</span>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-body">
|
||||||
|
<label :for="'motion' + index + '_pin'">{{ $t('triggers.motionPin') }}</label>
|
||||||
|
<input type="number" :id="'motion' + index + '_pin'" v-model.number="trigger.pin">
|
||||||
|
|
||||||
|
<label :for="'motion' + index + '_direction'">{{ $t('triggers.motionDirection') }}</label>
|
||||||
|
<select :id="'motion' + index + '_direction'" v-model.number="trigger.direction">
|
||||||
|
<option value="1">{{ $t('triggers.motionDirectionNonDirectional') }}</option>
|
||||||
|
<option value="2">{{ $t('triggers.motionDirectionTopDown') }}</option>
|
||||||
|
<option value="3">{{ $t('triggers.motionDirectionBottomUp') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div class="step">
|
||||||
|
<span class="value">{{ Math.floor(trigger.brightness / 255 * 100) }}%</span>
|
||||||
|
<div class="slidercontainer">
|
||||||
|
<input type="range" min="0" max="255" class="slider" v-model.number="trigger.brightness">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="nodata">
|
||||||
|
{{ $t('triggers.motionNoData') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<button class="button-primary button-outline" :disabled="saving" @click.prevent="addMotionTrigger">{{ $t('triggers.motionAdd') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<input class="button-primary" type="submit" :disabled="saving" :value="saving ? $t('applyButtonSaving') : $t('applyButton')">
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -294,7 +354,7 @@
|
|||||||
<h3>{{ $t('system.mapsTitle') }}</h3>
|
<h3>{{ $t('system.mapsTitle') }}</h3>
|
||||||
|
|
||||||
<label for="mapsAPIKey">{{ $t('system.mapsAPIKey') }}</label>
|
<label for="mapsAPIKey">{{ $t('system.mapsAPIKey') }}</label>
|
||||||
<input type="number" id="mapsAPIKey" v-model.number="system.mapsAPIKey">
|
<input type="text" id="mapsAPIKey" v-model.number="system.mapsAPIKey">
|
||||||
<span class="hint">{{ $t('system.mapsAPIKeyhint') }}</span>
|
<span class="hint">{{ $t('system.mapsAPIKeyhint') }}</span>
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
|
48
web/lang.js
48
web/lang.js
@ -40,10 +40,14 @@ var messages = {
|
|||||||
timeTitle: 'Time',
|
timeTitle: 'Time',
|
||||||
timeInternet: 'Please note that time triggers require an internet connection.',
|
timeInternet: 'Please note that time triggers require an internet connection.',
|
||||||
timeNoData: 'No time triggers defined yet',
|
timeNoData: 'No time triggers defined yet',
|
||||||
|
|
||||||
|
timeEnabled: 'Enable time triggers',
|
||||||
|
timeTransitionTime: 'Transition time in milliseconds',
|
||||||
|
|
||||||
timeAdd: 'Add',
|
timeAdd: 'Add',
|
||||||
timeDelete: 'Delete',
|
timeDelete: 'Delete',
|
||||||
|
|
||||||
timeEnabled: 'Enabled',
|
timeTriggerEnabled: 'Enabled',
|
||||||
timeFixedTime: 'Fixed time',
|
timeFixedTime: 'Fixed time',
|
||||||
timeSunrise: 'Sunrise',
|
timeSunrise: 'Sunrise',
|
||||||
timeSunset: 'Sunset',
|
timeSunset: 'Sunset',
|
||||||
@ -57,7 +61,22 @@ var messages = {
|
|||||||
timeSaturday: 'Saturday',
|
timeSaturday: 'Saturday',
|
||||||
timeSunday: 'Sunday',
|
timeSunday: 'Sunday',
|
||||||
|
|
||||||
motionTitle: 'Motion'
|
motionTitle: 'Motion',
|
||||||
|
motionNoData: 'No motion triggers defined yet',
|
||||||
|
|
||||||
|
motionEnabled: 'Enable motion triggers',
|
||||||
|
motionEnabledDuringTimeTrigger: 'Activate even if a time trigger is already active',
|
||||||
|
motionTransitionTime: 'Transition time in milliseconds',
|
||||||
|
|
||||||
|
motionTriggerEnabled: 'Enabled',
|
||||||
|
motionAdd: 'Add',
|
||||||
|
motionDelete: 'Delete',
|
||||||
|
|
||||||
|
motionPin: 'GPIO pin (active high)',
|
||||||
|
motionDirection: 'Sweep animation',
|
||||||
|
motionDirectionNonDirectional: 'None (all steps at the same time)',
|
||||||
|
motionDirectionTopDown: 'Top down',
|
||||||
|
motionDirectionBottomUp: 'Bottom up'
|
||||||
},
|
},
|
||||||
|
|
||||||
connection: {
|
connection: {
|
||||||
@ -97,7 +116,7 @@ var messages = {
|
|||||||
|
|
||||||
pinLEDAP: 'Access Point status LED pin (+3.3v)',
|
pinLEDAP: 'Access Point status LED pin (+3.3v)',
|
||||||
pinLEDSTA: 'Station Mode status LED pin (+3.3v)',
|
pinLEDSTA: 'Station Mode status LED pin (+3.3v)',
|
||||||
pinAPButton: 'Enable Access Point button pin (pull low)',
|
pinAPButton: 'Enable Access Point button pin (active low)',
|
||||||
pinPWMDriverSDA: 'PCA9685 PWM driver SDA pin (data)',
|
pinPWMDriverSDA: 'PCA9685 PWM driver SDA pin (data)',
|
||||||
pinPWMDriverSCL: 'PCA9685 PWM driver SCL pin (clock)',
|
pinPWMDriverSCL: 'PCA9685 PWM driver SCL pin (clock)',
|
||||||
pwmAddress: 'PCA9685 PWM driver I²C address',
|
pwmAddress: 'PCA9685 PWM driver I²C address',
|
||||||
@ -149,10 +168,14 @@ var messages = {
|
|||||||
timeTitle: 'Tijd',
|
timeTitle: 'Tijd',
|
||||||
timeInternet: 'Let op dat voor tijd triggers een internetverbinding vereist is.',
|
timeInternet: 'Let op dat voor tijd triggers een internetverbinding vereist is.',
|
||||||
timeNoData: 'Nog geen tijd triggers geconfigureerd',
|
timeNoData: 'Nog geen tijd triggers geconfigureerd',
|
||||||
|
|
||||||
|
timeEnabled: 'Tijd triggers inschakelen',
|
||||||
|
timeTransitionTime: 'Transitie tijd in milliseconden',
|
||||||
|
|
||||||
timeAdd: 'Toevoegen',
|
timeAdd: 'Toevoegen',
|
||||||
timeDelete: 'Verwijderen',
|
timeDelete: 'Verwijderen',
|
||||||
|
|
||||||
timeEnabled: 'Actief',
|
timeTriggerEnabled: 'Actief',
|
||||||
timeFixedTime: 'Vaste tijd',
|
timeFixedTime: 'Vaste tijd',
|
||||||
timeSunrise: 'Zonsopkomst',
|
timeSunrise: 'Zonsopkomst',
|
||||||
timeSunset: 'Zonsondergang',
|
timeSunset: 'Zonsondergang',
|
||||||
@ -166,7 +189,22 @@ var messages = {
|
|||||||
timeSaturday: 'Zaterdag',
|
timeSaturday: 'Zaterdag',
|
||||||
timeSunday: 'Zondag',
|
timeSunday: 'Zondag',
|
||||||
|
|
||||||
motionTitle: 'Beweging'
|
motionTitle: 'Beweging',
|
||||||
|
motionNoData: 'Nog geen beweging triggers geconfigureerd',
|
||||||
|
|
||||||
|
motionEnabled: 'Beweging triggers inschakelen',
|
||||||
|
motionEnabledDuringTimeTrigger: 'Ook inschakelen als er al een tijd trigger actief is',
|
||||||
|
motionTransitionTime: 'Transitie tijd in milliseconden',
|
||||||
|
|
||||||
|
motionTriggerEnabled: 'Actief',
|
||||||
|
motionAdd: 'Toevoegen',
|
||||||
|
motionDelete: 'Verwijderen',
|
||||||
|
|
||||||
|
motionPin: 'GPIO pin (actief hoog)',
|
||||||
|
motionDirection: 'Animatie',
|
||||||
|
motionDirectionNonDirectional: 'Geen (alle treden gelijktijdig)',
|
||||||
|
motionDirectionTopDown: 'Boven naar beneden',
|
||||||
|
motionDirectionBottomUp: 'Beneden naar boven'
|
||||||
},
|
},
|
||||||
|
|
||||||
connection: {
|
connection: {
|
||||||
|
@ -12,6 +12,7 @@ $containerBackgroundColor: #202020;
|
|||||||
$containerShadow: 0 0 50px #fcf6cf;
|
$containerShadow: 0 0 50px #fcf6cf;
|
||||||
|
|
||||||
$panelBorderColor: #404040;
|
$panelBorderColor: #404040;
|
||||||
|
$panelBodyBackgroundColor: #242422;
|
||||||
$panelHeaderBackgroundColor: #302f28;
|
$panelHeaderBackgroundColor: #302f28;
|
||||||
$panelHeaderColor: #808080;
|
$panelHeaderColor: #808080;
|
||||||
$panelHeaderLinkColor: white;
|
$panelHeaderLinkColor: white;
|
||||||
@ -331,6 +332,7 @@ input[disabled]
|
|||||||
|
|
||||||
& .panel-body
|
& .panel-body
|
||||||
{
|
{
|
||||||
|
background-color: $panelBodyBackgroundColor;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user