@@ -112,6 +112,7 @@ public ServiceAnswers getAnswersPool(String language) {
112112 private static final String okAnswer = ServiceAnswers .ANS_PREFIX + CMD_NAME + "_still_ok_0a" ;
113113 private static final String deviceStateSet = ServiceAnswers .ANS_PREFIX + CMD_NAME + "_state_set_0a" ;
114114 private static final String deviceStateShow = ServiceAnswers .ANS_PREFIX + CMD_NAME + "_state_show_0a" ;
115+ private static final String askStateValue = "smartdevice_1d" ;
115116 private static final String failAnswer = "error_0a" ;
116117 private static final String notAllowed = "smartdevice_0d" ;
117118
@@ -168,6 +169,7 @@ public ServiceInfo getInfo(String language) {
168169 .addOkayAnswer (okAnswer )
169170 .addCustomAnswer ("setState" , deviceStateSet ) //adding these answers here is optional and used just as info
170171 .addCustomAnswer ("showState" , deviceStateShow )
172+ .addCustomAnswer ("askStateValue" , askStateValue )
171173 .addCustomAnswer ("notAllowed" , notAllowed )
172174 ;
173175
@@ -244,23 +246,13 @@ public ServiceResult getResult(NluResult nluResult) {
244246 }else if (typeIsEqual (deviceType , SmartDevice .Types .light )){
245247 //SHOW lights status
246248 if (typeIsEqual (actionType , Action .Type .show )){
247- //find device - we always load a fresh list
248- Map < String , SmartHomeDevice > devices = smartHomeHUB . getDevices ( );
249- if (devices == null ){
249+ //find device
250+ SmartHomeDevice selectedDevice = findDevice ( smartHomeHUB , deviceType , roomType );
251+ if (selectedDevice == null ){
250252 //FAIL
251- service .setStatusFail (); //"hard"-fail (probably connection or token error)
253+ service .setStatusFail (); //TODO: improve answers (error, no match, etc.) with service.setCustomAnswer(...);
252254 return service .buildResult ();
253255 }else {
254- //get all devices with right type and optionally right room
255- List <SmartHomeDevice > matchingDevices = SmartOpenHAB .getMatchingDevices (devices , deviceType , roomType , -1 );
256- //have found any?
257- if (matchingDevices .isEmpty ()){
258- service .setStatusOkay ();
259- //service.setCustomAnswer(noDeviceMatchesFound); //TODO: improve answer
260- return service .buildResult ();
261- }
262- //keep only the first match for now - TODO: improve
263- SmartHomeDevice selectedDevice = matchingDevices .get (0 );
264256 String state = selectedDevice .getState ();
265257 String name = selectedDevice .getName ();
266258
@@ -276,6 +268,36 @@ public ServiceResult getResult(NluResult nluResult) {
276268 //System.out.println(selectedDevice.getDeviceAsJson());
277269 }
278270
271+ //SET lights status
272+ }else if (typeIsEqual (actionType , Action .Type .set )){
273+ //check if we have a value or need to ask
274+ String targetSetValue = deviceValue .getValueAsString (); //NOTE: we have more options here than only "VALUE"
275+ if (targetSetValue .isEmpty ()){
276+ service .setIncompleteAndAsk (PARAMETERS .SMART_DEVICE_VALUE , askStateValue );
277+ return service .buildResult ();
278+ }
279+ //find device
280+ SmartHomeDevice selectedDevice = findDevice (smartHomeHUB , deviceType , roomType );
281+ if (selectedDevice == null ){
282+ //FAIL
283+ service .setStatusFail (); //TODO: improve answers (error, no match, etc.) with service.setCustomAnswer(...);
284+ return service .buildResult ();
285+ }else {
286+ boolean setSuccess = smartHomeHUB .setDeviceState (selectedDevice , "pct " + targetSetValue ); //we assume percentage here, TODO: use parameter info to decide
287+ if (setSuccess ){
288+ //response info
289+ String name = selectedDevice .getName ();
290+ service .resultInfoPut ("device_name" , name );
291+ service .resultInfoPut ("device_value" , SmartOpenHAB .getStateLocal (targetSetValue , service .language ));
292+ //answer
293+ service .setCustomAnswer (deviceStateSet );
294+ }else {
295+ //fail answer
296+ service .setStatusFail (); //"hard"-fail (probably openHAB connection error)
297+ return service .buildResult ();
298+ }
299+ }
300+
279301 //Other light actions?
280302 }else {
281303 //OK but no result
@@ -322,6 +344,24 @@ private static boolean typeIsEqual(String value, Enum<?> type){
322344 return value .equals (type .name ());
323345 }
324346
347+ private SmartHomeDevice findDevice (SmartHomeHub smartHomeHUB , String deviceType , String roomType ){
348+ //find device - we always load a fresh list
349+ Map <String , SmartHomeDevice > devices = smartHomeHUB .getDevices ();
350+ if (devices == null ){
351+ return null ;
352+ }else {
353+ //get all devices with right type and optionally right room
354+ List <SmartHomeDevice > matchingDevices = SmartOpenHAB .getMatchingDevices (devices , deviceType , roomType , -1 );
355+ //have found any?
356+ if (matchingDevices .isEmpty ()){
357+ return null ;
358+ }
359+ //keep only the first match for now - TODO: improve
360+ SmartHomeDevice selectedDevice = matchingDevices .get (0 );
361+ return selectedDevice ;
362+ }
363+ }
364+
325365 //------------- FHEM ------------- //TODO: move to server
326366
327367 public static class Fhem implements SmartHomeHub {
@@ -446,13 +486,36 @@ public Map<String, SmartHomeDevice> getDevices(){
446486 return null ;
447487 }
448488 }
489+
490+ //TODO: add override annotation in SEPIA v2.3.2+
491+ public boolean writeDeviceAttribute (SmartHomeDevice device , String attrName , String attrValue ){
492+ String fhemId = device .getMetaValueAsString ("fhem-id" );
493+ String deviceCmdLink = device .getLink ();
494+ if (Is .nullOrEmpty (fhemId ) || Is .nullOrEmpty (deviceCmdLink )){
495+ return false ;
496+ }else {
497+ String cmdUrl = URLBuilder .getString (
498+ deviceCmdLink , "=" , "attr " + fhemId + " " + attrName + " " + attrValue ,
499+ "&XHR=" , "1" ,
500+ "&fwcsrf=" , this .csrfToken
501+ );
502+ JSONObject response = Connectors .httpGET (cmdUrl );
503+ //System.out.println("RESPONSE: " + response); //this is usually empty if there was no error
504+ return Connectors .httpSuccess (response );
505+ }
506+ }
449507
450508 @ Override
451509 public SmartHomeDevice loadDeviceData (SmartHomeDevice device ){
452- String deviceURL = "" ; //TODO - build this: http://localhost:8083/fhem?cmd=jsonlist2%20MyHueBridge_HUEDevice1&XHR=1&fwcsrf=csrf_680293651159739
453- if (Is .nullOrEmpty (deviceURL )){
510+ String fhemId = device . getMetaValueAsString ( "fhem-id" );
511+ if (Is .nullOrEmpty (fhemId )){
454512 return null ;
455513 }else {
514+ String deviceURL = URLBuilder .getString (this .host ,
515+ "?cmd=" , "jsonlist2 " + fhemId ,
516+ "&XHR=" , "1" ,
517+ "&fwcsrf=" , this .csrfToken
518+ );
456519 JSONObject response = Connectors .httpGET (deviceURL );
457520 if (Connectors .httpSuccess (response )){
458521 //build shd from response
@@ -465,15 +528,27 @@ public SmartHomeDevice loadDeviceData(SmartHomeDevice device){
465528 }
466529
467530 @ Override
468- public boolean setDeviceState (SmartHomeDevice arg0 , String arg1 ){
469- // TODO Auto-generated method stub
470- return false ;
531+ public boolean setDeviceState (SmartHomeDevice device , String state ){
532+ String fhemId = device .getMetaValueAsString ("fhem-id" );
533+ String deviceCmdLink = device .getLink ();
534+ if (Is .nullOrEmpty (fhemId ) || Is .nullOrEmpty (deviceCmdLink )){
535+ return false ;
536+ }else {
537+ String cmdUrl = URLBuilder .getString (
538+ deviceCmdLink , "=" , "set " + fhemId + " " + state ,
539+ "&XHR=" , "1" ,
540+ "&fwcsrf=" , this .csrfToken
541+ );
542+ //System.out.println("URL: " + cmdUrl); //DEBUG
543+ JSONObject response = Connectors .httpGET (cmdUrl );
544+ //System.out.println("RESPONSE: " + response); //this is usually empty if there was no error
545+ return Connectors .httpSuccess (response );
546+ }
471547 }
472548
473549 @ Override
474- public boolean setDeviceStateMemory (SmartHomeDevice arg0 , String arg1 ){
475- // TODO Auto-generated method stub
476- return false ;
550+ public boolean setDeviceStateMemory (SmartHomeDevice device , String memState ){
551+ return writeDeviceAttribute (device , "sepia-mem-state" , memState ); //TODO: replace with SmartHomeDevice.SEPIA_TAG_NAME in SEPIA v2.3.2+
477552 }
478553
479554 //------------- FHEM specific helper methods --------------
@@ -540,7 +615,7 @@ private SmartHomeDevice buildDeviceFromResponse(JSONObject hubDevice){
540615 String fhemObjName = JSON .getStringOrDefault (hubDevice , "Name" , null );
541616 //JSONObject stateObj = JSON.getJObject(hubDevice, new String[]{"Readings", "state"});
542617 //String state = (stateObj != null)? JSON.getString(stateObj, "Value") : null;
543- String state = JSON .getStringOrDefault (internals , "STATE" , null );
618+ String state = JSON .getStringOrDefault (internals , "STATE" , null ); //TODO: think about states like 'dim50%'
544619 Object linkObj = (fhemObjName != null )? (this .host + "?cmd." + fhemObjName ) : null ;
545620 JSONObject meta = JSON .make (
546621 "fhem-id" , fhemObjName
@@ -551,7 +626,6 @@ private SmartHomeDevice buildDeviceFromResponse(JSONObject hubDevice){
551626 (linkObj != null )? linkObj .toString () : null , meta );
552627 return shd ;
553628 }
554-
555629 }
556630
557631}
0 commit comments