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

Sunspec #1784

Closed
wants to merge 88 commits into from
Closed

Sunspec #1784

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
6d9df51
Initial commit
rpochet May 12, 2023
a414d5f
Round values
rpochet May 13, 2023
3d90c63
Merge branch 'master' into sunspec
rpochet May 13, 2023
bae784a
Update package.json
rpochet May 13, 2023
db9601b
Update package.json
rpochet May 13, 2023
0945ee0
Merge branch 'sunspec' of https://github.com/rpochet/Gladys into sunspec
rpochet May 13, 2023
d65b8bb
Tests
rpochet May 23, 2023
4e49b4a
Tests
rpochet May 23, 2023
dd46227
Merge branch 'sunspec' of https://github.com/rpochet/Gladys into sunspec
rpochet May 23, 2023
7e8fa73
Merge branch 'master' into sunspec
rpochet May 24, 2023
644e937
Tests
rpochet May 24, 2023
42cafeb
Tests
rpochet May 24, 2023
9148473
Tests
rpochet May 24, 2023
fa6d51b
Merge branch 'master' into sunspec
rpochet May 27, 2023
3fe369f
Merge branch 'master' into sunspec
rpochet Jun 15, 2023
316c601
Merge branch 'master' into sunspec
rpochet Jun 15, 2023
7d7c553
Tests
rpochet Jun 15, 2023
9a10dca
Tests
rpochet Jun 16, 2023
b4e2e4a
Merge branch 'master' into sunspec
rpochet Jun 16, 2023
41c8a4b
Tests
rpochet Jun 23, 2023
39fb9bd
Merge branch 'sunspec' of https://github.com/rpochet/Gladys into sunspec
rpochet Jun 23, 2023
7f19f58
Poll
rpochet Jun 23, 2023
cb2a5cb
Poll
rpochet Jun 23, 2023
d0c2c7e
Poll
rpochet Jun 24, 2023
76d74ca
Poll
rpochet Jun 25, 2023
38e2c3f
BDPV
rpochet Jul 8, 2023
660ebdb
Merge branch 'master' into sunspec
rpochet Jul 28, 2023
a7a797d
Merge branch 'sunspec' of https://github.com/rpochet/Gladys into sunspec
rpochet Aug 18, 2023
1c4c88b
Add Sunspec isUsed
rpochet Aug 18, 2023
fb582b2
Merge branch 'master' into sunspec
rpochet Aug 21, 2023
5e5d28b
Merge branch 'GladysAssistant:master' into sunspec
rpochet Aug 28, 2023
7bd6306
Review naming
rpochet Aug 29, 2023
a12a82e
Tests
rpochet Aug 30, 2023
8bb1177
Merge branch 'GladysAssistant:master' into sunspec
rpochet Aug 31, 2023
b9a3c36
Tests
rpochet Aug 31, 2023
fe7d4a2
Tests
rpochet Aug 31, 2023
448abd9
Tests
rpochet Sep 1, 2023
af83d06
Tests
rpochet Sep 1, 2023
dbd9d0e
Tests
rpochet Sep 1, 2023
2492a99
Tests
rpochet Sep 4, 2023
f8640af
Merge branch 'master' into sunspec
rpochet Sep 4, 2023
30832e4
BDPV unit report
rpochet Sep 4, 2023
4ff421c
Merge branch 'master' into sunspec
rpochet Sep 12, 2023
73700ac
Merge branch 'sunspec' of https://github.com/rpochet/Gladys into sunspec
rpochet Sep 13, 2023
4452e08
Add AC device
rpochet Sep 15, 2023
042f6f8
Add AC device
rpochet Sep 15, 2023
cedb0a9
Add AC device
rpochet Sep 15, 2023
d974144
Prettier
rpochet Sep 15, 2023
0f411dc
Tests
rpochet Sep 18, 2023
d0aef57
Tests
rpochet Sep 18, 2023
0625078
Scan for modbus devices
rpochet Sep 22, 2023
a49c4d5
Merge branch 'GladysAssistant:master' into sunspec
rpochet Sep 22, 2023
04456c1
Tests
rpochet Sep 22, 2023
411f2cc
Merge branch 'sunspec' of https://github.com/rpochet/Gladys into sunspec
rpochet Sep 22, 2023
91691e5
Tests
rpochet Sep 22, 2023
ad7efe4
Tests
rpochet Sep 23, 2023
96b3079
Tests
rpochet Sep 23, 2023
5ab59c2
Tests
rpochet Sep 24, 2023
97fabc2
Tests
rpochet Sep 27, 2023
b8652bc
Tests
rpochet Sep 27, 2023
c6eb6e4
Merge branch 'master' into sunspec
rpochet Sep 27, 2023
b6fef2f
Tests
rpochet Sep 27, 2023
f95f04a
Tests
rpochet Sep 27, 2023
93ab064
Merge branch 'sunspec' of https://github.com/rpochet/Gladys into sunspec
rpochet Sep 27, 2023
e501e13
Tests
rpochet Sep 27, 2023
e9f920b
Tests
rpochet Sep 27, 2023
35b3a6e
Tests
rpochet Sep 28, 2023
32e53c9
Merge branch 'master' into sunspec
rpochet Sep 28, 2023
af6b41e
BDPV
rpochet Oct 6, 2023
3d4252c
Merge branch 'sunspec' of https://github.com/rpochet/Gladys into sunspec
rpochet Oct 6, 2023
f6b83bc
BDPV
rpochet Oct 6, 2023
01a60cf
BDPV
rpochet Oct 6, 2023
df83005
Merge branch 'master' into sunspec
rpochet Oct 6, 2023
6d0f6c8
BDPV
rpochet Oct 6, 2023
61bd0b7
Add logs
rpochet Oct 9, 2023
c0f7383
Check device feature exist
rpochet Oct 9, 2023
c07f06d
Merge branch 'GladysAssistant:master' into sunspec
rpochet Oct 9, 2023
2904069
Merge branch 'GladysAssistant:master' into sunspec
rpochet Oct 16, 2023
5489084
Refactor
rpochet Oct 17, 2023
554935f
Merge branch 'sunspec' of https://github.com/rpochet/Gladys into sunspec
rpochet Oct 17, 2023
9612012
Refactor
rpochet Oct 17, 2023
34627c5
Merge branch 'master' into sunspec
rpochet Oct 23, 2023
4d8f73c
Bug fix
rpochet Nov 2, 2023
e9ac2bc
Tests
rpochet Nov 2, 2023
59b0020
Merge branch 'GladysAssistant:master' into sunspec
rpochet Nov 9, 2023
3f2cd78
Bug fix check.test
rpochet Nov 10, 2023
15a2c5a
Merge branch 'master' into sunspec
rpochet Nov 10, 2023
ea11d28
Tests
rpochet Nov 20, 2023
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
Binary file added front/src/assets/integrations/cover/sunspec.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions front/src/components/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ import EweLinkSetupPage from '../routes/integration/all/ewelink/setup-page';
// OpenAI integration
import OpenAIPage from '../routes/integration/all/openai/index';

// SunSpec integration
import SunSpecDevicePage from '../routes/integration/all/sunspec/device-page';
import SunSpecDiscoverPage from '../routes/integration/all/sunspec/discover-page';
import SunSpecSettingsPage from '../routes/integration/all/sunspec/settings-page';

// Tuya integration
import TuyaPage from '../routes/integration/all/tuya/device-page';
import TuyaEditPage from '../routes/integration/all/tuya/edit-page';
Expand Down Expand Up @@ -295,6 +300,10 @@ const AppRouter = connect(
<LANManagerDiscoverPage path="/dashboard/integration/device/lan-manager/discover" />
<LANManagerSettingsPage path="/dashboard/integration/device/lan-manager/config" />

<SunSpecDevicePage path="/dashboard/integration/device/sunspec" />
<SunSpecDiscoverPage path="/dashboard/integration/device/sunspec/discover" />
<SunSpecSettingsPage path="/dashboard/integration/device/sunspec/config" />

<GoogleHomeWelcomePage path="/dashboard/integration/communication/googlehome" />
<GoogleHomeGateway path="/dashboard/integration/device/google-home/authorize" />
<AlexaWelcomePage path="/dashboard/integration/communication/alexa" />
Expand Down
66 changes: 65 additions & 1 deletion front/src/config/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1418,7 +1418,64 @@
"activateOpenAiChat": "Activate ChatGPT in Gladys chat",
"rateLimit": "As ChatGPT API is not free, this integration is limited to 1000 requests per month.",
"notOnGladysPlus": "As ChatGPT API is not free, this integration is only available to Gladys Plus users.",
"subscribeToGladysPlus": "<a href=\"https://gladysassistant.com/plus/\" target=\"_blank\" rel=\"noopener noreferrer\">Click here</a> to subscribe to Gladys Plus."
"subscribeToGladysPlus": "<a href=\"https://gladysassistant.com/plus/\" target=\"_blank\" rel=\"noopener noreferrer\">Click here</a> to subscribe to Gladys Plus.",
"licenseShouldBeActive": "This integration is only available to users with an active license (at least one payment). For trial users, please contact us on the forum or email."
},
"sunspec": {
"title": "SunSpec",
"description": "Manage you SunSpec device through you local network.",
"deviceTab": "Devices",
"discoverTab": "Discover",
"settingsTab": "Settings",
"device": {
"title": "SunSpec Devices",
"search": "Search devices",
"noDevices": "No SunSpec devices added yet.",
"manufacturerLabel": "Manufacturer",
"ipAddressLabel": "IP address",
"macAddressLabel": "MAC address",
"originalNameLabel": "Hostname"
},
"discover": {
"title": "SunSpec Discover",
"noDevices": "No SunSpec devices found.",
"scanButton": "Scan network",
"deviceUpdateButton": "New devices available",
"hideExistingDevices": "Hide already added devices",
"alreadyCreatedButton": "Already created",
"updateButton": "Update",
"discoveringError": "An error occurred, check scanner configuration, or check logs."
},
"settings": {
"title": "SunSpec settings",
"errorLabel": "An error occurred while loading configuration.",
"noConfigLabel": "Configuration not loaded, please retry.",
"sunspecUrl": "SunSpec URL",
"sunspecUrlPlaceholder": "Ex: [sunspec-address]:[port]",
"bdpvActiveLabel": "Activate BDPV Synchronisation",
"userLabel": "Nom d'utilisateur",
"userPlaceholder": "Entrez le nom d'utilisateur BDPV",
"apiKeyLabel": "Clé API",
"apiKeyPlaceholder": "Entrez la clé API",
"fronius": {
"description": "Activate Modbus TCP on Fronius inverters",
"documentation": "Fronius Documentation"
},
"sma": {
"description": "Activate Modbus TCP on SAM inverters",
"documentation": "SMA Documentation"
},
"ipMasksLabel": "CIDR to scan",
"masksDescription": "CIDR (Classless Inter-Domain Routing) is a notation to describe a range of IP addresses in a sub-network. You can write it as an IP address, followed by a network mask number, both separated by a slash (example: 192.168.1.1/10). There is many CIDR calculators on the Internet which will help you to compute your own.",
"networkInterfaceDescription": "Masks defined by your computer on your networks, with network interfaces, can't be removed.",
"maskTableHeader": "CIDR",
"nameTableHeader": "Name",
"statusTableHeader": "Active",
"maskTablePlaceholder": "e.g. 192.168.1.1/20",
"nameTablePlaceholder": "Enter CIDR name",
"deleteButtonTooltip": "Delete",
"maskFormatError": "Invalid CIDR format"
}
}
},
"editScene": {
Expand Down Expand Up @@ -2666,6 +2723,13 @@
"shortCategoryName": "Air Quality",
"aqi": "Air Quality Index"
},
"pv": {
"shortCategoryName": "Photovoltaic",
"voltage": "Voltage",
"current": "Current",
"power": "Power",
"energy": "Energy"
},
"text": {
"shortCategoryName": "Text",
"text": "Text"
Expand Down
66 changes: 65 additions & 1 deletion front/src/config/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1419,7 +1419,64 @@
"activateOpenAiChat": "Activer ChatGPT dans le chat Gladys",
"rateLimit": "L'API ChatGPT étant payante, cette intégration est actuellement limitée à 1 000 requêtes par mois et par compte.",
"notOnGladysPlus": "L'API ChatGPT étant payante, cette intégration est proposée via Gladys Plus uniquement.",
"subscribeToGladysPlus": "<a href=\"https://gladysassistant.com/fr/plus/\" target=\"_blank\" rel=\"noopener noreferrer\">Cliquez-ici</a> pour souscrire à Gladys Plus."
"subscribeToGladysPlus": "<a href=\"https://gladysassistant.com/fr/plus/\" target=\"_blank\" rel=\"noopener noreferrer\">Cliquez-ici</a> pour souscrire à Gladys Plus.",
"licenseShouldBeActive": "Cette intégration n'est disponible qu'aux utilisateurs Gladys Plus dont l'abonnement est actuellement actif avec au moins un paiement. Pour les utilisateurs en périodes d'essai, merci de me contacter sur le forum ou par email !"
},
"sunspec": {
"title": "SunSpec Manager",
"description": "Gérez les appareils SunSpec sur votre réseau local.",
"deviceTab": "Appareils",
"discoverTab": "Découverte",
"settingsTab": "Configuration",
"device": {
"title": "Appareils SunSpec",
"search": "Chercher un appareil",
"noDevices": "Aucun appareil SunSpec n'a encore été ajouté.",
"manufacturerLabel": "Construteur",
"ipAddressLabel": "Adresse IP",
"macAddressLabel": "Adresse MAC",
"originalNameLabel": "Nom sur le réseau"
},
"discover": {
"title": "Découverte SunSpec",
"noDevices": "Aucun appareil SunSpec n'a encore été trouvé.",
"scanButton": "Recherche sur le réseau",
"deviceUpdateButton": "Nouveaux appareils disponibles",
"hideExistingDevices": "Cacher les appareils déjà ajoutés",
"alreadyCreatedButton": "Déjà créé",
"updateButton": "Mettre à jour",
"discoveringError": "Une erreur est survenue lors de la recherche, vérifiez la configuration du scanner, sinon consultez les logs."
},
"settings": {
"title": "Configuration SunSpec",
"errorLabel": "Une erreur est survenue lors du chargement de la configuration.",
"noConfigLabel": "La configuration n'est pas chargée, merci de réessayer.",
"sunspecUrl": "SunSpec URL",
"sunspecUrlPlaceholder": "Ex: [sunspec-address]:[port]",
"bdpvActiveLabel": "Activer la synchronisation BDPV",
"userLabel": "Nom d'utilisateur",
"userPlaceholder": "Entrez le nom d'utilisateur BDPV",
"apiKeyLabel": "Clé API",
"apiKeyPlaceholder": "Entrez la clé API",
"fronius": {
"description": "Activez l'interface Modbus TCP sur les onduleurs Fronius",
"documentation": "Documentation Fronius"
},
"sma": {
"description": "Activez l'interface Modbus TCP sur les onduleurs SMA",
"documentation": "Documentation SMA"
},
"ipMasksLabel": "CIDR à scanner",
"masksDescription": "La notation CIDR (Classless Inter-Domain Routing) permet de définir un masque de sous-réseau, c'est à dire une plage d'IP. Sa syntaxe correspond à une adresse IP du réseau, suivi d'un nombre, le masque, séparés par une barre oblique (exemple : 192.168.1.1/10). Il existe de multiples calculateurs d'adresse CIDR sur Internet qui vous aideront à composer celles qui vont correspondent le mieux.",
"networkInterfaceDescription": "Les masques enregistrés par votre ordinateur, selon les interfaces réseaux, ne peuvent pas être supprimés.",
"maskTableHeader": "CIDR",
"nameTableHeader": "Nom",
"statusTableHeader": "Actif",
"maskTablePlaceholder": "e.g. 192.168.1.1/20",
"nameTablePlaceholder": "Entrer le nom du CIDR",
"deleteButtonTooltip": "Supprimer",
"maskFormatError": "Format CIDR invalide"
}
}
},
"editScene": {
Expand Down Expand Up @@ -2667,6 +2724,13 @@
"shortCategoryName": "Qualité de l'air",
"aqi": "Indice de qualité de l'air"
},
"pv": {
"shortCategoryName": "Photovoltaique",
"voltage": "Tension",
"current": "Intensité",
"power": "Puissance",
"energy": "Energie"
},
"text": {
"shortCategoryName": "Texte",
"text": "Texte"
Expand Down
4 changes: 4 additions & 0 deletions front/src/config/integrations/devices.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
"link": "lan-manager",
"img": "/assets/integrations/cover/lan-manager.jpg"
},
{
"key": "sunspec",
"img": "/assets/integrations/cover/sunspec.png"
},
{
"key": "tuya",
"link": "tuya",
Expand Down
14 changes: 14 additions & 0 deletions front/src/routes/integration/all/sunspec/EmptyState.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Text } from 'preact-i18n';
import cx from 'classnames';

import style from './style.css';

const EmptyState = ({ id }) => (
<div class={cx('col-md-12', style.emptyStateDivBox)}>
<div class="text-center">
<Text id={id} />
</div>
</div>
);

export default EmptyState;
60 changes: 60 additions & 0 deletions front/src/routes/integration/all/sunspec/SunSpecPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Text } from 'preact-i18n';
import { Link } from 'preact-router/match';

const SunSpecPage = ({ children }) => (
<div class="page">
<div class="page-main">
<div class="my-3 my-md-5">
<div class="container">
<div class="row">
<div class="col-lg-3">
<h3 class="page-title mb-5">
<Text id="integration.sunspec.title" />
</h3>
<div>
<div class="list-group list-group-transparent mb-0">
<Link
href="/dashboard/integration/device/sunspec"
activeClassName="active"
class="list-group-item list-group-item-action d-flex align-items-center"
>
<span class="icon mr-3">
<i class="fe fe-link" />
</span>
<Text id="integration.sunspec.deviceTab" />
</Link>

<Link
href="/dashboard/integration/device/sunspec/discover"
activeClassName="active"
class="list-group-item list-group-item-action d-flex align-items-center"
>
<span class="icon mr-3">
<i class="fe fe-radio" />
</span>
<Text id="integration.sunspec.discoverTab" />
</Link>

<Link
href="/dashboard/integration/device/sunspec/config"
activeClassName="active"
class="list-group-item list-group-item-action d-flex align-items-center"
>
<span class="icon mr-3">
<i class="fe fe-settings" />
</span>
<Text id="integration.sunspec.settingsTab" />
</Link>
</div>
</div>
</div>

<div class="col-lg-9">{children}</div>
</div>
</div>
</div>
</div>
</div>
);

export default SunSpecPage;
117 changes: 117 additions & 0 deletions front/src/routes/integration/all/sunspec/device-page/SunSpecDevice.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { Text, Localizer, MarkupText } from 'preact-i18n';
import { Component } from 'preact';
import cx from 'classnames';
import get from 'get-value';

import { RequestStatus } from '../../../../../utils/consts';
import DeviceFeatures from '../../../../../components/device/view/DeviceFeatures';

class SunSpecDevice extends Component {
saveDevice = async () => {
this.setState({ loading: true });
try {
await this.props.saveDevice(this.props.deviceIndex);
} catch (e) {
this.setState({ error: RequestStatus.Error });
}
this.setState({ loading: false });
};
deleteDevice = async () => {
this.setState({ loading: true, tooMuchStatesError: false, statesNumber: undefined });
try {
await this.props.deleteDevice(this.props.device, this.props.deviceIndex);
} catch (e) {
const status = get(e, 'response.status');
const dataMessage = get(e, 'response.data.message');
if (status === 400 && dataMessage && dataMessage.includes('Too much states')) {
const statesNumber = new Intl.NumberFormat().format(dataMessage.split(' ')[0]);
this.setState({ tooMuchStatesError: true, statesNumber });
} else {
this.setState({ error: RequestStatus.Error });
}
}
this.setState({ loading: false });
};
updateName = e => {
this.props.updateDeviceProperty(this.props.deviceIndex, 'name', e.target.value);
};
updateRoom = e => {
this.props.updateDeviceProperty(this.props.deviceIndex, 'room_id', e.target.value);
};

render({ device, houses }, { loading, tooMuchStatesError, statesNumber }) {
return (
<div class="col-md-6">
<div class="card">
<div class="card-header">{device.name}</div>
<div
class={cx('dimmer', {
active: loading
})}
>
<div class="loader" />
<div class="dimmer-content">
<div class="card-body">
{tooMuchStatesError && (
<div class="alert alert-warning">
<MarkupText id="device.tooMuchStatesToDelete" fields={{ count: statesNumber }} />
</div>
)}
<div class="form-group">
<label class="form-label">
<Text id="editDeviceForm.nameLabel" />
</label>
<Localizer>
<input
type="text"
value={device.name}
onInput={this.updateName}
class="form-control"
placeholder={<Text id="editDeviceForm.namePlaceholder" />}
/>
</Localizer>
</div>
<div class="form-group">
<label class="form-label">
<Text id="editDeviceForm.roomLabel" />
</label>
<select onChange={this.updateRoom} class="form-control">
<option value="">
<Text id="global.emptySelectOption" />
</option>
{houses &&
houses.map(house => (
<optgroup label={house.name}>
{house.rooms.map(room => (
<option selected={room.id === device.room_id} value={room.id}>
{room.name}
</option>
))}
</optgroup>
))}
</select>
</div>
<div class="form-group">
<label class="form-label">
<Text id="editDeviceForm.featuresLabel" />
</label>
<DeviceFeatures features={device.features} />
</div>
<div class="form-group">
<button onClick={this.saveDevice} class="btn btn-success mr-2">
<Text id="editDeviceForm.saveButton" />
</button>
<button onClick={this.deleteDevice} class="btn btn-danger">
<Text id="editDeviceForm.deleteButton" />
</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}

export default SunSpecDevice;
Loading
Loading