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、控制点可以为电脑,智能手机。