]> git.basschouten.com Git - openhab-addons.git/blob
f7bd45eefa2dcc761d80e0bbcd27e644fd7398e1
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.homematic.internal.type.generator;
14
15 import java.io.BufferedReader;
16 import java.io.BufferedWriter;
17 import java.io.File;
18 import java.io.FileOutputStream;
19 import java.io.IOException;
20 import java.io.InputStreamReader;
21 import java.io.OutputStreamWriter;
22 import java.net.URL;
23 import java.util.Date;
24 import java.util.Map;
25 import java.util.Map.Entry;
26 import java.util.TreeMap;
27
28 /**
29  * The CcuMetadataExtractor loads some JavaScript files from the CCU and generates the device and datapoint
30  * descriptions into the file generated-descriptions.properties.
31  * Not all descriptions can be generated, because they are spread across many files and were partly assembled.
32  * To add the missing descriptions or to override a generated, use the extra-descriptions.properties file.
33  *
34  * @author Gerhard Riegler - Initial contribution
35  */
36 public class CcuMetadataExtractor {
37     private static final String CCU_URL = "http://ccu";
38
39     private static final String DEVICE_KEYS = "/webui/webui.js";
40     private static final String DESCRIPTION_KEYS = "/webui/js/lang/{LANGUAGE}/translate.lang.stringtable.js";
41     private static final String DESCRIPTION_DESCRIPTIONS = "/webui/js/lang/{LANGUAGE}/translate.lang.deviceDescription.js";
42
43     private static final String MASTER_LANG_PATH = "/config/easymodes/MASTER_LANG/";
44     private static final String[] MASTER_LANG_FILES = { "HEATINGTHERMOSTATE_2ND_GEN.js", "HM_ES_PMSw.js" };
45
46     private static final String[] LANGUAGES = { "en", "de" };
47
48     /**
49      * Starts the extractor and generates the file.
50      */
51     public static void main(String[] args) {
52         try {
53             CcuMetadataExtractor dg = new CcuMetadataExtractor();
54             dg.generate();
55
56         } catch (IOException ex) {
57             System.err.println(ex.getMessage());
58         }
59     }
60
61     /**
62      * Loads the JavaScript file from the CCU and generates the properties file.
63      */
64     private void generate() throws IOException {
65         Map<String, String> deviceKeys = loadDeviceKeys();
66
67         for (String lang : LANGUAGES) {
68             // load datapoint descriptions
69             Map<String, String> langDescriptions = loadJsonLangDescriptionFile(CCU_URL + DESCRIPTION_KEYS, lang);
70             for (String fileName : MASTER_LANG_FILES) {
71                 langDescriptions.putAll(loadJsonLangDescriptionFile(CCU_URL + MASTER_LANG_PATH + fileName, lang));
72             }
73
74             // load device descriptions
75             Map<String, String> deviceDescriptions = loadJsonLangDescriptionFile(CCU_URL + DESCRIPTION_DESCRIPTIONS,
76                     lang);
77
78             String langIdent = ("en".equals(lang) ? "" : "_" + lang);
79             File file = new File("./src/main/resources/homematic/generated-descriptions" + langIdent + ".properties");
80             System.out.println("Writing file " + file.getAbsolutePath());
81             if (file.exists()) {
82                 file.delete();
83             }
84             file.createNewFile();
85             BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
86
87             // write device descriptions
88             bw.write("# -------------- generated descriptions " + new Date() + " --------------\n");
89             bw.write("# DON'T CHANGE THIS FILE!\n\n");
90             for (Entry<String, String> entry : deviceDescriptions.entrySet()) {
91                 bw.write(entry.getKey());
92                 bw.write("=");
93                 bw.write(entry.getValue());
94                 bw.write("\n");
95             }
96
97             bw.write("\n\n\n");
98
99             // write datapoint descriptions
100             for (Entry<String, String> entry : deviceKeys.entrySet()) {
101                 String description = langDescriptions.get(entry.getValue());
102                 if (description == null) {
103                     System.out.println("WARNING: Can't find a translation for " + entry.getValue());
104                 } else {
105                     bw.write(entry.getKey().toUpperCase());
106                     bw.write("=");
107                     bw.write(description);
108                     bw.write("\n");
109                 }
110             }
111
112             bw.flush();
113             bw.close();
114         }
115     }
116
117     /**
118      * Loads a JavaScript file and extract JSON description data.
119      */
120     private Map<String, String> loadJsonLangDescriptionFile(String url, String lang) throws IOException {
121         final Map<String, String> descriptions = new TreeMap<>();
122         String descriptionUrl = url.replace("{LANGUAGE}", lang);
123
124         String startLine = "  \"" + lang + "\" : {";
125         String endLine = "  },";
126
127         new UrlLoader(descriptionUrl, startLine, endLine) {
128             @Override
129             public void line(String line) {
130                 String[] entry = handleStringTable(line);
131                 if (entry != null) {
132                     descriptions.put(entry[0].trim(), unescape(entry[1].trim()));
133                 }
134             }
135         };
136         return descriptions;
137     }
138
139     /**
140      * Loads all description keys.
141      */
142     private Map<String, String> loadDeviceKeys() throws IOException {
143         final Map<String, String> deviceKeys = new TreeMap<>();
144
145         new UrlLoader(CCU_URL + DEVICE_KEYS) {
146
147             @Override
148             public void line(String line) {
149                 if (line.startsWith("elvST['")) {
150                     line = line.replace("elvST['", "");
151                     line = line.replace("'] = '", "=");
152                     line = line.replace("';", "");
153                     line = line.replace("$", "");
154                     line = line.replace("{", "");
155                     line = line.replace("}", "");
156
157                     int count = 0;
158                     for (int i = 0; i < line.length(); i++) {
159                         if (line.charAt(i) == '=') {
160                             count++;
161                         }
162                     }
163                     if (count > 1) {
164                         line = line.replaceFirst("=", "|");
165                     }
166                     String[] split = line.split("=", 2);
167                     deviceKeys.put(split[0].trim(), split[1].trim());
168                 }
169             }
170         };
171         return deviceKeys;
172     }
173
174     /**
175      * Splits a JSON JavaScript entry.
176      */
177     private String[] handleStringTable(String line) {
178         line = line.replace("    \"", "");
179         line = line.replace("\",", "");
180         line = line.replace("\"", "");
181
182         String[] splitted = line.split(":", 2);
183         return splitted.length != 2 ? null : splitted;
184     }
185
186     /**
187      * Transforms a string for a Java property file.
188      */
189     private String unescape(String str) {
190         str = str.replace("%FC", "ü");
191         str = str.replace("%DC", "Ü");
192         str = str.replace("%E4", "ä");
193         str = str.replace("%C4", "Ä");
194         str = str.replace("%F6", "ö");
195         str = str.replace("%D6", "Ö");
196         str = str.replace("%DF", "ß");
197         str = str.replace("&nbsp;", "");
198         str = str.replace("<br/>", " ");
199         str = str.replace("&uuml;", "ü");
200         str = str.replace("&auml;", "ä");
201         str = str.replace("&ouml;", "ö");
202         str = str.replace("&Uuml;", "Ü");
203         str = str.replace("&Auml;", "Ä");
204         str = str.replace("&Ouml;", "Ö");
205         return str;
206     }
207
208     /**
209      * Simple class to load a CCU resource.
210      */
211     private abstract class UrlLoader {
212         public UrlLoader(String url) throws IOException {
213             this(url, null, null);
214         }
215
216         public UrlLoader(String url, String startLine, String endLine) throws IOException {
217             System.out.println("Loading file " + url);
218             Boolean includeLine = null;
219             BufferedReader br = new BufferedReader(new InputStreamReader(new URL(url).openStream(), "UTF-8"));
220
221             String line;
222             while ((line = br.readLine()) != null) {
223                 if (startLine != null) {
224                     if (line.equals(startLine)) {
225                         includeLine = true;
226                         continue;
227                     } else if (line.equals(endLine) || includeLine == null) {
228                         includeLine = false;
229                     }
230                 }
231                 if ((includeLine == null || includeLine) && !line.isBlank()) {
232                     line(line);
233                 }
234             }
235             br.close();
236         }
237
238         public abstract void line(String line);
239     }
240 }