package example.binarylight; import org.teleal.cling.binding.annotations.UpnpAction; import org.teleal.cling.binding.annotations.UpnpInputArgument; import org.teleal.cling.binding.annotations.UpnpOutputArgument; import org.teleal.cling.binding.annotations.UpnpService; import org.teleal.cling.binding.annotations.UpnpServiceId; import org.teleal.cling.binding.annotations.UpnpServiceType; import org.teleal.cling.binding.annotations.UpnpStateVariable; @UpnpService( serviceId = @UpnpServiceId("ElectricfanService"), //serviceId serviceType = @UpnpServiceType(value = "ElectricfanService", version = 1) //SERVICE TYPE 和版本 ) public class ElectricfanService { @UpnpStateVariable(defaultValue = "0", sendEvents = false) private boolean target = false; @UpnpStateVariable(defaultValue = "0") private boolean status = false; @UpnpAction public void setTarget(@UpnpInputArgument(name = "NewTargetValue") boolean newTargetValue) { target = newTargetValue; status = newTargetValue; System.out.println("myService is: " + status); } @UpnpAction(out = @UpnpOutputArgument(name = "RetTargetValue")) public boolean getTarget() { return target; } @UpnpAction(out = @UpnpOutputArgument(name = "ResultStatus")) public boolean getStatus() { return status; } @UpnpStateVariable(defaultValue = "0", sendEvents = false) private String aa; @UpnpAction public void setAa(@UpnpInputArgument(name = "rr") String rr) { aa = rr; System.out.println("myService setAa is: " + rr); } }
1、 target和status是官方文档里面例子,暂时不明白为什么需要两个参数。
2、@UpnpStateVariable(defaultValue = "0", sendEvents = false)
private String aa;
可以直接改为:
@UpnpStateVariable
private String aa;
不知道这样有什么影响。
3、aa是自己写的变量,使用string类型,提供一个action方法,要求符合java bean规范:setAa这种写法。rr是控制点传入参数Key值,输入输出使用key value的形式。
4、控制点调用如下:
基本使用官方demo
package example.binarylight; import java.net.URI; import java.net.URISyntaxException; import org.teleal.cling.UpnpService; import org.teleal.cling.UpnpServiceImpl; import org.teleal.cling.controlpoint.ActionCallback; import org.teleal.cling.model.action.ActionInvocation; import org.teleal.cling.model.message.UpnpResponse; import org.teleal.cling.model.message.header.STAllHeader; import org.teleal.cling.model.meta.RemoteDevice; import org.teleal.cling.model.meta.Service; import org.teleal.cling.model.types.InvalidValueException; import org.teleal.cling.model.types.ServiceId; import org.teleal.cling.model.types.UDAServiceId; import org.teleal.cling.registry.DefaultRegistryListener; import org.teleal.cling.registry.Registry; import org.teleal.cling.registry.RegistryListener; public class ElectricfanClient implements Runnable { public static void main(String[] args) throws Exception { // Start a user thread that runs the UPnP stack Thread clientThread = new Thread(new ElectricfanClient()); clientThread.setDaemon(false); clientThread.start(); } public void run() { try { UpnpService upnpService = new UpnpServiceImpl(); // Add a listener for device registration events upnpService.getRegistry().addListener( createRegistryListener(upnpService) ); // Broadcast a search message for all devices upnpService.getControlPoint().search( new STAllHeader() ); } catch (Exception ex) { System.err.println("Exception occured: " + ex); System.exit(1); } } // DOC: REGISTRYLISTENER RegistryListener createRegistryListener(final UpnpService upnpService) { return new DefaultRegistryListener() { ServiceId serviceId = new UDAServiceId("ElectricfanService"); @Override public void remoteDeviceAdded(Registry registry, RemoteDevice device) { Service switchPower; if ((switchPower = device.findService(serviceId)) != null) { System.out.println("Service discovered: " + switchPower); executeAction(upnpService, switchPower); } } @Override public void remoteDeviceRemoved(Registry registry, RemoteDevice device) { Service switchPower; if ((switchPower = device.findService(serviceId)) != null) { System.out.println("Service disappeared: " + switchPower); } } }; } // DOC: REGISTRYLISTENER // DOC: EXECUTEACTION void executeAction(UpnpService upnpService, Service switchPowerService) { ActionInvocation setTargetInvocation = new SetTargetActionInvocation(switchPowerService); // Executes asynchronous in the background upnpService.getControlPoint().execute( new ActionCallback(setTargetInvocation) { @Override public void success(ActionInvocation invocation) { assert invocation.getOutput().length == 0; System.out.println("Successfully called action!"); } @Override public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) { System.err.println(defaultMsg); } } ); } // class SetTargetActionInvocation extends ActionInvocation { // // SetTargetActionInvocation(Service service) { // super(service.getAction("SetTarget")); // try { // // // Throws InvalidValueException if the value is of wrong type // setInput("NewTargetValue", true); // // } catch (InvalidValueException ex) { // System.err.println(ex.getMessage()); // System.exit(1); // } // } // } class SetTargetActionInvocation extends ActionInvocation { SetTargetActionInvocation(Service service) { super(service.getAction("SetAa")); try { // Throws InvalidValueException if the value is of wrong type setInput("rr", "1234"); } catch (InvalidValueException ex) { System.err.println(ex.getMessage()); System.exit(1); } } } // DOC: EXECUTEACTION }
主要区别在于:
1、 ServiceId serviceId = new UDAServiceId("ElectricfanService");
定义为自己需要的service
2、 super(service.getAction("SetAa"));
调用自己定义的action
3、传入自己的key value
setInput("rr", "1234");
以上基本实现控制点控制设备的服务功能。
按照理解,UPnP-av-ContentDirectory-v1-Service应该也是通过这种方式的,无非自己定义通讯的key value,加上设备需要启动一个web容器,然后提供对外资源暴露的功能。
以控制电风扇例子为例,简单家电需要提供的服务如下:
1、开关功能。 (电风扇开关)
2、功能列表查询功能。 (档位控制,定时控制)
3、具体功能控制
a、档位增减
b、定时多少
一般设备功能:
1、开关
2、控制量的增减
3、定时
难点:
1、设备要求支持网络模块(upnp协议)以及服务的实现
2、控制点可以为电脑,智能手机。