@@ -48,6 +48,17 @@ public class FhemDemo implements ServiceInterface {
4848 //Command name of your service (will be combined with userId to be unique, e.g. 'uid1007.python_bridge')
4949 private static final String CMD_NAME = "fhem" ;
5050
51+ //TODO: add in SEPIA v2.3.2
52+ /*
53+ @Override
54+ public ServiceRequirements getRequirements(){
55+ return new ServiceRequirements()
56+ .serverMinVersion("2.3.2")
57+ .apiAccess(ServiceRequirements.Apis.fhem)
58+ ;
59+ }
60+ */
61+
5162 //Define some sentences for testing:
5263
5364 @ Override
@@ -177,7 +188,7 @@ public ServiceResult getResult(NluResult nluResult) {
177188
178189 //this services uses the 'SmartHomeHub' interface
179190 String smartHomeHubHost = "http://localhost:8083/fhem" ;
180- SmartHomeHub smartHomeHUB = new Fhem (smartHomeHubHost );
191+ Fhem smartHomeHUB = new Fhem (smartHomeHubHost ); //TODO: replace with 'SmartHomeHub' in SEPIA v2.3.2
181192
182193 //get required parameters
183194 Parameter device = nluResult .getRequiredParameter (PARAMETERS .SMART_DEVICE );
@@ -196,6 +207,12 @@ public ServiceResult getResult(NluResult nluResult) {
196207 //Device is FHEM server itself?
197208 if (typeIsEqual (deviceType , SmartDevice .Types .device ) && deviceName .equals ("FHEM" )){
198209 if (typeIsEqual (actionType , Action .Type .show )){
210+ //check if SEPIA is registered - if not try to register
211+ if (!smartHomeHUB .registerSepiaFramework ()){
212+ //FAIL
213+ service .setStatusFail (); //"hard"-fail (probably connection or token error)
214+ return service .buildResult ();
215+ }
199216 //get devices
200217 Map <String , SmartHomeDevice > devices = smartHomeHUB .getDevices ();
201218 if (devices == null ){
@@ -205,7 +222,7 @@ public ServiceResult getResult(NluResult nluResult) {
205222 }else {
206223 //list devices
207224 for (SmartHomeDevice shd : devices .values ()){
208- service .addToExtendedLog ("device: " + shd .getDeviceAsJson ().toJSONString ());
225+ service .addToExtendedLog ("device: " + shd .getDeviceAsJson ().toJSONString ()); //DEBUG
209226 }
210227 //all good
211228 service .setStatusSuccess ();
@@ -254,14 +271,20 @@ private static boolean typeIsEqual(String value, Enum<?> type){
254271 return value .equals (type .name ());
255272 }
256273
257- //------------- FHEM -------------
274+ //------------- FHEM ------------- //TODO: move to server
258275
259276 public static class Fhem implements SmartHomeHub {
260277
261278 private String host ;
262279 private String csrfToken = "" ;
263280 public static final String NAME = "fhem" ;
264281
282+ private static final String TAG_NAME = "sepia-name" ; //TODO: replace with SmartHomeDevice.SEPIA_TAG_.. in SEPIA v2.3.2
283+ private static final String TAG_TYPE = "sepia-type" ;
284+ private static final String TAG_ROOM = "sepia-room" ;
285+ private static final String TAG_DATA = "sepia-data" ;
286+ private static final String TAG_MEM_STATE = "sepia-mem-state" ;
287+
265288 /**
266289 * Create new FHEM instance and automatically get CSRF token.
267290 * @param host - e.g.: http://localhost:8083/fhem
@@ -287,6 +310,55 @@ public Fhem(String host, String csrfToken){
287310 this .csrfToken = csrfToken ;
288311 }
289312 }
313+
314+ //TODO: add override annotation in SEPIA v2.3.2+
315+ public boolean registerSepiaFramework (){
316+ //Find attributes first
317+ String foundAttributes = "" ;
318+ String getUrl = URLBuilder .getString (this .host ,
319+ "?cmd=" , "jsonlist2 global" ,
320+ "&XHR=" , "1" ,
321+ "&fwcsrf=" , this .csrfToken
322+ );
323+ try {
324+ //Call and check
325+ JSONObject resultGet = Connectors .httpGET (getUrl );
326+ if (Connectors .httpSuccess (resultGet ) && JSON .getIntegerOrDefault (resultGet , "totalResultsReturned" , 0 ) == 1 ){
327+ foundAttributes = (String ) JSON .getJObject ((JSONObject ) JSON .getJArray (resultGet , "Results" ).get (0 ), "Attributes" ).get ("userattr" );
328+ if (Is .nullOrEmpty (foundAttributes )){
329+ Debugger .println ("FHEM - registerSepiaFramework: Failed! No existing 'userattr' found in 'global' attributes. Please add manually." , 1 );
330+ return false ;
331+ }else {
332+ //System.out.println("foundAttributes: " + foundAttributes); //DEBUG
333+ //check if attributes are already there (if one is there all should be there ...)
334+ if (foundAttributes .matches (".*\\ b" + TAG_NAME + "\\ b.*" )){
335+ return true ;
336+ }
337+ }
338+ }else {
339+ Debugger .println ("FHEM - registerSepiaFramework: Failed! Could not load global attributes. Msg.: " + resultGet .toJSONString (), 1 );
340+ return false ;
341+ }
342+ //Register FHEM means adding the SEPIA tags to global attributes
343+ String setUrl = URLBuilder .getString (this .host ,
344+ "?cmd=" , "attr global userattr " + foundAttributes + " " + TAG_NAME + " " + TAG_TYPE + " " + TAG_ROOM + " " + TAG_DATA + " " + TAG_MEM_STATE ,
345+ "&XHR=" , "1" ,
346+ "&fwcsrf=" , this .csrfToken
347+ );
348+ JSONObject resultSet = Connectors .httpGET (setUrl );
349+ if (Connectors .httpSuccess (resultSet )){
350+ //all good
351+ return true ;
352+ }else {
353+ Debugger .println ("FHEM - registerSepiaFramework: Failed! Could not set global attributes. Msg.: " + resultSet .toJSONString (), 1 );
354+ return false ;
355+ }
356+ }catch (Exception e ){
357+ Debugger .println ("FHEM - registerSepiaFramework: Failed! Error: " + e .getMessage (), 1 );
358+ Debugger .printStackTrace (e , 3 );
359+ return false ;
360+ }
361+ }
290362
291363 @ Override
292364 public Map <String , SmartHomeDevice > getDevices (){
@@ -375,7 +447,7 @@ private SmartHomeDevice buildDeviceFromResponse(JSONObject hubDevice){
375447 String memoryState = "" ;
376448 if (attributes != null ){
377449 //try to find self-defined SEPIA tags first
378- name = JSON .getStringOrDefault (attributes , "sepia-name" , null );
450+ name = JSON .getStringOrDefault (attributes , "sepia-name" , null ); //TODO: replace with SmartHomeDevice.SEPIA_TAG_NAME in SEPIA v2.3.2+
379451 type = JSON .getStringOrDefault (attributes , "sepia-type" , null );
380452 room = JSON .getStringOrDefault (attributes , "sepia-room" , null );
381453 memoryState = JSON .getStringOrDefault (attributes , "sepia-mem-state" , null );
@@ -390,9 +462,9 @@ private SmartHomeDevice buildDeviceFromResponse(JSONObject hubDevice){
390462 }
391463 if (type == null && internals != null ){
392464 String fhemType = JSON .getString (internals , "type" ).toLowerCase ();
393- if (fhemType .matches ("(.*\\ s|^)(light.*|lamp.*)" )){
465+ if (fhemType .matches ("(.*\\ s|^|, )(light.*|lamp.*)" )){
394466 type = SmartDevice .Types .light .name (); //LIGHT
395- }else if (fhemType .matches ("(.*\\ s|^)(heat.*|thermo.*)" )){
467+ }else if (fhemType .matches ("(.*\\ s|^|, )(heat.*|thermo.*)" )){
396468 type = SmartDevice .Types .heater .name (); //HEATER
397469 }else {
398470 type = fhemType ; //take this if we don't have a specific type yet
@@ -406,8 +478,10 @@ private SmartHomeDevice buildDeviceFromResponse(JSONObject hubDevice){
406478 String fhemObjName = JSON .getStringOrDefault (hubDevice , "Name" , null );
407479 Object stateObj = JSON .getObject (hubDevice , new String []{"Readings" , "state" });
408480 Object linkObj = (fhemObjName != null )? (this .host + "?cmd." + fhemObjName ) : null ;
409- JSONObject meta = null ;
410- //TODO: we could add some stuff to meta when we need other data from response.
481+ JSONObject meta = JSON .make (
482+ "fhem-id" , fhemObjName
483+ );
484+ //note: we need fhem-id for commands although it is basically already in 'link'
411485 SmartHomeDevice shd = new SmartHomeDevice (name , type , room ,
412486 (stateObj != null )? stateObj .toString () : null , memoryState ,
413487 (linkObj != null )? linkObj .toString () : null , meta );
0 commit comments