Skip to content

Commit

Permalink
EDF Tempo widget + condition in scene (#2056)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierre-Gilles authored Apr 22, 2024
1 parent 5151c99 commit 5d444f9
Show file tree
Hide file tree
Showing 24 changed files with 941 additions and 1 deletion.
1 change: 1 addition & 0 deletions front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"serve": "sirv build --port 8080 --cors --single",
"dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider preact watch -p 1444 --template src/template.html",
"start-gateway": "cross-env GATEWAY_MODE=true NODE_OPTIONS=--openssl-legacy-provider preact watch -p 1445 --template src/template.html",
"start-demo": "cross-env DEMO_MODE=true NODE_OPTIONS=--openssl-legacy-provider preact watch -p 1445 --template src/template.html",
"eslint": "eslint src cypress --ext .json --ext .js --ext .jsx",
"compare-translations": "comparejson -e ./src/config/i18n/*.json && node ./cli/check_translations.js",
"prettier-check": "prettier --check '**/*.js' '**/*.jsx' '**/*.json'",
Expand Down
181 changes: 181 additions & 0 deletions front/src/components/boxs/edf-tempo/EdfTempo.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import { Component } from 'preact';
import { Text } from 'preact-i18n';
import { connect } from 'unistore/preact';
import cx from 'classnames';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
import style from './style.css';

dayjs.extend(utc);
dayjs.extend(timezone);

// Refresh EDF Tempo data every 1 hour
const BOX_REFRESH_INTERVAL_MS = 1 * 60 * 60 * 1000;

const PeakState = ({ state }) => (
<div>
{state === 'blue' && (
<span class="badge badge-primary">
<Text id="dashboard.boxes.edfTempo.blueDay" />
</span>
)}
{state === 'white' && (
<span class="badge badge-light text-dark">
<Text id="dashboard.boxes.edfTempo.whiteDay" />
</span>
)}
{state === 'red' && (
<span class="badge badge-danger">
<Text id="dashboard.boxes.edfTempo.redDay" />
</span>
)}
{state === 'not-defined' && (
<span class="badge badge-dark">
<Text id="dashboard.boxes.edfTempo.notDefinedDay" />
</span>
)}
</div>
);

const EdfTempoBox = ({ loading, error, today, tomorrow, currentHourPeakState, todayPeakState, tomorrowPeakState }) => (
<div class="card">
<div class="card-header">
<h3 class="card-title">
<i class="fe fe-zap" />
<span class="m-1">
<Text id="dashboard.boxTitle.edf-tempo" />
</span>
</h3>
</div>
<div class="card-body">
<div class={`dimmer ${loading ? 'active' : ''}`}>
<div class="loader" />
{error && (
<p class="alert alert-danger">
<i class="fe fe-bell" />
<span class="pl-2">
<Text id="dashboard.boxes.edfTempo.error" />
</span>
</p>
)}
{!error && (
<div class="dimmer-content">
<div class="row mb-1">
<div class="col">
{currentHourPeakState === 'peak-hour' && (
<div
class={cx(style.hourDisplay, style.peakHour, 'd-flex align-items-center justify-content-center')}
>
<i class="fe fe-sun mr-4" />
<Text id="dashboard.boxes.edfTempo.peakHour" />
</div>
)}
{currentHourPeakState === 'off-peak-hour' && (
<div
class={cx(style.hourDisplay, style.offPeakHour, 'd-flex align-items-center justify-content-center')}
>
<i class="fe fe-moon mr-4" />
<Text id="dashboard.boxes.edfTempo.offPeakHour" />
</div>
)}
</div>
</div>
<div class="mt-3">
<h4 class={style.h4Title}>
<Text id="dashboard.boxes.edfTempo.dayPeakTitle" />
</h4>
<div class="row mb-1">
<div class="col">{today}</div>
<div class="col-auto">
<PeakState state={todayPeakState} />
</div>
</div>
<div class="row mb-1">
<div class="col">{tomorrow}</div>
<div class="col-auto">
<PeakState state={tomorrowPeakState} />
</div>
</div>
</div>
</div>
)}
</div>
</div>
</div>
);

class EdfTempo extends Component {
refreshData = async () => {
try {
await this.setState({ error: false, loading: true });
const edfTempoData = await this.props.httpClient.get('/api/v1/service/edf-tempo/state');
const today = dayjs()
.locale(this.props.user.language)
.format('ddd LL');
const tomorrow = dayjs()
.add(1, 'day')
.locale(this.props.user.language)
.format('ddd LL');

const todayPeakState = edfTempoData.today_peak_state;
const tomorrowPeakState = edfTempoData.tomorrow_peak_state;

this.setState({
error: false,
loading: false,
today,
tomorrow,
todayPeakState,
tomorrowPeakState
});
} catch (e) {
this.setState({ error: true, loading: false });
}
};

refreshPeakHourState = () => {
const today = dayjs();
const todayHour = today.tz('Europe/Paris').hour();
const currentHourPeakState = todayHour >= 6 && todayHour < 22 ? 'peak-hour' : 'off-peak-hour';
this.setState({ currentHourPeakState });
};

componentDidMount() {
this.refreshPeakHourState();
this.refreshData();
this.interval = setInterval(() => this.refreshData(), BOX_REFRESH_INTERVAL_MS);
// Every minute, refresh peak hour state
this.peakHourRefreshInterval = setInterval(() => this.refreshPeakHourState(), 60 * 1000);
}

componentWillUnmount() {
clearInterval(this.interval);
clearInterval(this.peakHourRefreshInterval);
}

constructor(props) {
super(props);
this.props = props;
this.state = {
loading: true,
error: false
};
}

render({}, { loading, error, today, tomorrow, currentHourPeakState, todayPeakState, tomorrowPeakState }) {
return (
<EdfTempoBox
loading={loading}
error={error}
today={today}
tomorrow={tomorrow}
currentHourPeakState={currentHourPeakState}
todayPeakState={todayPeakState}
tomorrowPeakState={tomorrowPeakState}
/>
);
}
}

export default connect('httpClient,user', {})(EdfTempo);
21 changes: 21 additions & 0 deletions front/src/components/boxs/edf-tempo/EditEdfTempo.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Text } from 'preact-i18n';
import BaseEditBox from '../baseEditBox';

const EditEdfTempo = ({ ...props }) => (
<BaseEditBox {...props} titleKey="dashboard.boxTitle.edf-tempo">
<Text id="dashboard.boxes.edfTempo.description" />{' '}
<div>
<small>
<a
href="https://particulier.edf.fr/fr/accueil/gestion-contrat/options/tempo.html#/"
target="_blank"
rel="noopener noreferrer"
>
<Text id="dashboard.boxes.edfTempo.link" />
</a>
</small>
</div>
</BaseEditBox>
);

export default EditEdfTempo;
24 changes: 24 additions & 0 deletions front/src/components/boxs/edf-tempo/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.h4Title {
font-size: 16px;
}

.hourDisplay {
width: 100%;
padding: 0.5rem 1rem;
font-size: 1.25rem;
line-height: 1.5;
border-radius: 0.3rem;
text-align: 'center';
}

.peakHour {
color: #f1c40f;
background-color: transparent;
background-image: none;
border-color: #f1c40f;
border: 1px solid;
}

.offPeakHour {
border: 1px solid;
}
10 changes: 9 additions & 1 deletion front/src/config/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ const data = {
type: 'devices-in-room',
room: 'exterior',
device_features: ['aqi-city']
},
{
type: 'edf-tempo'
}
],
[
Expand Down Expand Up @@ -4149,7 +4152,12 @@ const data = {
}
]
}
]
],
'get /api/v1/service/edf-tempo/state': {
today_peak_state: 'blue',
tomorrow_peak_state: 'blue',
current_hour_peak_state: 'peak-hour'
}
};

export default data;
31 changes: 31 additions & 0 deletions front/src/config/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@
"devices": "Geräte",
"chart": "Diagramm",
"ecowatt": "Ecowatt (Frankreich)",
"edf-tempo": "EDF Tempo",
"clock": "Uhr",
"scene": "Szene",
"music": "Musik"
Expand Down Expand Up @@ -369,6 +370,18 @@
"warning": "Netzwarnung",
"critical": "Netz kritisch"
},
"edfTempo": {
"description": "Dieses Widget ermöglicht es Ihnen, den aktuellen Zustand von EDF Tempo anzuzeigen.",
"link": "Mehr über EDF Tempo erfahren",
"blueDay": "Blauer Tag",
"whiteDay": "Weißer Tag",
"redDay": "Roter Tag",
"notDefinedDay": "Nicht definiert",
"currentHourState": "Aktuell",
"peakHour": "Hochtarifstunde",
"offPeakHour": "Niedrigtarifstunde",
"dayPeakTitle": "Tempo-Tage"
},
"clock": {
"analog": "Analog",
"digital": "Digital",
Expand Down Expand Up @@ -1804,6 +1817,21 @@
"warning": "Netzwarnung",
"critical": "Netz kritisch"
},
"edfTempoCondition": {
"description": "Die Szene wird fortgesetzt, wenn die untenstehenden Bedingungen für EDF Tempo erfüllt sind.",
"selectDay": "Für den Tag",
"today": "Heute",
"tomorrow": "Morgen",
"selectPeakDayType": "Wenn der Tag im",
"blueDay": "Blauen Tag",
"whiteDay": "Weißen Tag",
"redDay": "Roten Tag",
"noPeakDayCheck": "Beliebig",
"noPeakHourCheck": "Beliebig",
"selectPeakHourType": "Und wenn es",
"peakHour": "Hochtarifstunde",
"offPeakHour": "Niedrigtarifstunde"
},
"alarmCheckMode": {
"description": "Die Szene wird fortgesetzt, wenn die Alarmanlage im ausgewählten Modus ist.",
"houseLabel": "Zuhause",
Expand Down Expand Up @@ -1879,6 +1907,9 @@
"ecowatt": {
"condition": "Bedingung für Ecowatt (Frankreich)"
},
"edf-tempo": {
"condition": "Bedingung für EDF-Tempo"
},
"alarm": {
"check-alarm-mode": "Wenn der Alarm im Modus ist",
"set-alarm-mode": "Alarmmodus setzen auf"
Expand Down
31 changes: 31 additions & 0 deletions front/src/config/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@
"devices": "Devices",
"chart": "Chart",
"ecowatt": "Ecowatt (France)",
"edf-tempo": "Tempo EDF",
"clock": "Clock",
"scene": "Scene",
"music": "Music"
Expand Down Expand Up @@ -369,6 +370,18 @@
"warning": "Network warning",
"critical": "Network critical"
},
"edfTempo": {
"description": "This widget allows you to display the current EDF Tempo state.",
"link": "Learn more about EDF Tempo",
"blueDay": "Blue Day",
"whiteDay": "White Day",
"redDay": "Red Day",
"notDefinedDay": "Not Defined",
"currentHourState": "Currently",
"peakHour": "Peak Hour",
"offPeakHour": "Off-Peak Hour",
"dayPeakTitle": "Tempo days"
},
"clock": {
"analog": "Analog",
"digital": "Digital",
Expand Down Expand Up @@ -1804,6 +1817,21 @@
"warning": "Network warning",
"critical": "Network critical"
},
"edfTempoCondition": {
"description": "The scene will continue if the following conditions on EDF Tempo are met.",
"selectDay": "For the day",
"today": "Today",
"tomorrow": "Tomorrow",
"selectPeakDayType": "If the day is",
"blueDay": "Blue Day",
"whiteDay": "White Day",
"redDay": "Red Day",
"noPeakDayCheck": "Any",
"noPeakHourCheck": "Any",
"selectPeakHourType": "And if it's",
"peakHour": "Peak Hour",
"offPeakHour": "Off-Peak Hour"
},
"alarmCheckMode": {
"description": "The scene will continue if the alarm is in the selected mode.",
"houseLabel": "House",
Expand Down Expand Up @@ -1879,6 +1907,9 @@
"ecowatt": {
"condition": "Condition on Ecowatt (France)"
},
"edf-tempo": {
"condition": "Condition on EDF-Tempo"
},
"alarm": {
"check-alarm-mode": "If the alarm is in mode",
"set-alarm-mode": "Set alarm mode to"
Expand Down
Loading

0 comments on commit 5d444f9

Please sign in to comment.