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