Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Main page
Recent changes
Random page
freem
Search
Search
Appearance
Create account
Log in
Personal tools
Create account
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
Openai/691a15e5-9180-8001-a5a0-9b83ec27e6fe
(section)
Add languages
Page
Discussion
English
Read
Edit
Edit source
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit
Edit source
View history
General
What links here
Related changes
Special pages
Page information
Appearance
move to sidebar
hide
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
==== 10. EconnectClient.java – traduzione dal client Python ==== File: <code>src/main/java/org/openhab/binding/econnect/internal/client/EconnectClient.java</code> Qui ho usato gli stessi URL che vedo in elmo/systems.py e elmo/api/router.py del repo Python: * https://connect.elmospa.com (ELMO_E_CONNECT) * https://metronet.iessonline.com (IESS_METRONET) * endpoint /api/panel/authenticate, /api/panel/poll, /api/panel/check, /api/panel/syncSendCommand, /api/areas, /api/inputs, /api/outputs, ecc. La parte HTTP è già scritta; dove c’è da capire come interpretare il JSON (per mappare lo stato su DISARMED / ARMED_AWAY / ARMED_HOME / ARMED_NIGHT) ti ho lasciato dei TODO chiari. <syntaxhighlight lang="java">package org.openhab.binding.econnect.internal.client; import java.io.IOException; import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpClient.Redirect; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Map; import java.util.StringJoiner; import org.openhab.binding.econnect.internal.client.model.AlarmStatus; import org.openhab.binding.econnect.internal.client.model.AlarmStatus.Mode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Traduzione Java minima di ElmoClient (econnect-python). * * Nota: qui la parte HTTP è già pronta, ma la mappatura esatta del JSON * verso AlarmStatus va adattata guardando la risposta reale. */ public class EconnectClient implements AutoCloseable { private static final Logger logger = LoggerFactory.getLogger(EconnectClient.class); // URL prese da econnect-python/elmo/systems.py private static final String ELMO_E_CONNECT = "https://connect.elmospa.com"; private static final String IESS_METRONET = "https://metronet.iessonline.com"; private final String username; private final String password; private final String system; private final String domain; private final int refreshInterval; private final HttpClient httpClient; private String baseUrl; private String sessionId; public EconnectClient(String username, String password, String system, String baseUrlOverride, String domain, int refreshInterval) { this.username = username; this.password = password; this.system = system != null ? system : "elmo_econnect"; this.domain = domain; this.refreshInterval = refreshInterval; if (baseUrlOverride != null && !baseUrlOverride.isBlank()) { this.baseUrl = baseUrlOverride; } else { if ("iess_metronet".equalsIgnoreCase(this.system)) { this.baseUrl = IESS_METRONET; } else { this.baseUrl = ELMO_E_CONNECT; } } this.httpClient = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(10)) .followRedirects(Redirect.NORMAL) .build(); } // ------------------------------ // Endpoints (come Router in Python) // ------------------------------ private String urlAuth() { return baseUrl + "/api/panel/authenticate"; } private String urlPoll() { return baseUrl + "/api/panel/poll"; } private String urlCheck() { return baseUrl + "/api/panel/check"; } private String urlSendCommand() { return baseUrl + "/api/panel/syncSendCommand"; } private String urlSectors() { return baseUrl + "/api/areas"; } private String urlInputs() { return baseUrl + "/api/inputs"; } // ------------------------------ // Helper HTTP // ------------------------------ private static String buildQueryParams(Map<String, String> params) { StringJoiner joiner = new StringJoiner("&"); for (Map.Entry<String, String> e : params.entrySet()) { if (e.getValue() == null) continue; joiner.add(URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8) + "=" + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8)); } return joiner.toString(); } private HttpRequest.Builder baseGet(String url) { HttpRequest.Builder b = HttpRequest.newBuilder() .uri(URI.create(url)) .timeout(Duration.ofSeconds(15)) .GET(); if (sessionId != null) { b.header("SessionId", sessionId); } return b; } private HttpRequest.Builder basePost(String url, String bodyJson) { HttpRequest.Builder b = HttpRequest.newBuilder() .uri(URI.create(url)) .timeout(Duration.ofSeconds(15)) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(bodyJson)); if (sessionId != null) { b.header("SessionId", sessionId); } return b; } private String doRequest(HttpRequest request) throws IOException, InterruptedException { HttpResponse<String> resp = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); int status = resp.statusCode(); if (status < 200 || status >= 300) { throw new IOException("HTTP " + status + " - " + resp.body()); } return resp.body(); } // ------------------------------ // Autenticazione (auth()) // ------------------------------ public synchronized void authenticate() throws Exception { logger.debug("EconnectClient | authenticate"); String url = urlAuth(); String params = buildQueryParams(Map.of( "username", username, "password", password, "domain", domain )); if (!params.isEmpty()) { url = url + "?" + params; } HttpRequest req = baseGet(url).build(); String body = doRequest(req); /* * In econnect-python, dopo la auth: * - data["SessionId"] contiene il token di sessione * - data.get("Panel") contiene info sul pannello * * Qui per semplicità estraiamo solo SessionId con una parse brutale; * per qualcosa di pulito usa una libreria JSON (Jackson/Gson). */ String marker = "\"SessionId\":\""; int idx = body.indexOf(marker); if (idx == -1) { throw new IOException("SessionId non trovato nella risposta auth"); } int start = idx + marker.length(); int end = body.indexOf('"', start); if (end == -1) { throw new IOException("SessionId non ben formattato"); } sessionId = body.substring(start, end); logger.debug("EconnectClient | SessionId ottenuto"); } // ------------------------------ // Stato allarme (AlarmStatus) // ------------------------------ public synchronized AlarmStatus getAlarmStatus() throws Exception { logger.debug("EconnectClient | getAlarmStatus"); // Esempio minimo: leggiamo le aree e deduciamo lo stato. // In econnect-python c'è un metodo query() con query.SECTORS/INPUTS ecc. // Qui facciamo una GET su /api/areas. HttpRequest req = baseGet(urlSectors()).build(); String body = doRequest(req); /* * TODO: sostituisci questa logica con una vera analisi del JSON. * Ad esempio: * - se tutte le aree sono disarmate -> DISARMED * - se almeno una è armata totale -> ARMED_AWAY * - se qualche area è in home/night -> ARMED_HOME / ARMED_NIGHT * * Per ora, per avere codice compilabile, uso una semplificazione: */ Mode mode = Mode.DISARMED; if (body.contains("\"Armed\":true") || body.contains("\"armed\":true")) { mode = Mode.ARMED_AWAY; } return new AlarmStatus(mode); } // ------------------------------ // Comandi arm/disarm // ------------------------------ public synchronized void armAway() throws Exception { logger.debug("EconnectClient | armAway"); // In econnect-python: CommandType=1, ElementsClass=9 (sectors), ElementsIds=[] String json = "{" + "\"CommandType\":1," + "\"ElementsClass\":9," + "\"ElementsIds\":[]," + "\"TimeoutSeconds\":30" + "}"; HttpRequest req = basePost(urlSendCommand(), json).build(); doRequest(req); } public synchronized void armHome() throws Exception { logger.debug("EconnectClient | armHome"); /* * In ha-econnect-alarm la modalità "home" seleziona solo alcuni settori * configurati (vedi devices/helpers). Qui devi passare l'elenco di IDs * dei settori interessati. * * Metto un TODO con lista vuota (non fa nulla di “home” finché non la riempi). */ String json = "{" + "\"CommandType\":1," + "\"ElementsClass\":9," + "\"ElementsIds\":[]," + "\"TimeoutSeconds\":30" + "}"; HttpRequest req = basePost(urlSendCommand(), json).build(); doRequest(req); } public synchronized void armNight() throws Exception { logger.debug("EconnectClient | armNight"); // Come sopra, ma con un altro set di settori; TODO da adattare. String json = "{" + "\"CommandType\":1," + "\"ElementsClass\":9," + "\"ElementsIds\":[]," + "\"TimeoutSeconds\":30" + "}"; HttpRequest req = basePost(urlSendCommand(), json).build(); doRequest(req); } public synchronized void disarmAll() throws Exception { logger.debug("EconnectClient | disarmAll"); // In econnect-python: CommandType=2 (disarm), ElementsClass=9, ElementsIds=[] String json = "{" + "\"CommandType\":2," + "\"ElementsClass\":9," + "\"ElementsIds\":[]," + "\"TimeoutSeconds\":30" + "}"; HttpRequest req = basePost(urlSendCommand(), json).build(); doRequest(req); } @Override public void close() { // eventuale cleanup } } </syntaxhighlight>
Summary:
Please note that all contributions to freem are considered to be released under the Creative Commons Attribution-ShareAlike 4.0 (see
Freem:Copyrights
for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)