附上 API 地址:https://open.ys7.com/doc/zh/book/index/user.html
废话不多说直接上代码
/**
* @ProjectName: aila
* @Package: com.aila.fluorite.constnat
* @ClassName: CameraConstnat
* @Author: dujiayu
* @Description:
* @Date: 2022/1/18 11:48
* @Version: 1.0
*/
public class FluorConstant {
/**
* APP_KEY
*/
public static final String APP_KEY = "********************************";
/**
* SECRET
*/
public static final String SECRET = "********************************";
/**
* redis 存储accessToken 键
*/
public static final String REDIS_FLUOR_ACCESSTOKEN_KEY = "FLUOR_ACCESSTOKEN_KEY";
/**
* 缓存PC端选中查看过的监控设备序列号
*/
public static final String REDIS_FLUOR_VIDEO_LIST_KEY = "FLUOR_VIDEO_LIST_KEY";
/**
* 请求成功
*/
public static final String REQUEST_SUCCEESS = "200";
/**
* 重新获取accessToken
*/
public static final String TOKEN_EXPIRED = "10002";
/**
* 获取萤石开放平台AccessToken
*/
public static final String GETACCESSTOKEN_URL = "https://open.ys7.com/api/lapp/token/get";
/**
* 获取萤石IOT(物联网)AccessToken
*/
public static final String GETEZACCESSTOKEN_URL = "https://esopen.ys7.com/api/user/component-open/sso/oauth2/getEZAccessToken";
/**
* 获取用户下的设备列表
*/
public static final String DEVICE_SELECT_URL = "https://open.ys7.com/api/lapp/device/list";
/**
* 添加设备
*/
public static final String DEVICE_ADD_URL = "https://open.ys7.com/api/lapp/device/add";
/**
* 删除设备
*/
public static final String DEVICE_DELETE_URL = "https://open.ys7.com/api/lapp/device/delete";
/**
* 修改设备名称
*/
public static final String DEVICE_UPDATE_URL = "https://open.ys7.com/api/lapp/device/name/update";
/**
* 修改通道名称
*/
public static final String DEVICE_CAMERAUPDATE_URL = "https://open.ys7.com/api/lapp/camera/name/update";
/**
* 设备抓拍
*/
public static final String DEVICE_CAPTURE_URL = "https://open.ys7.com/api/lapp/device/capture";
/**
* 获取单个设备信息
*/
public static final String DEVICE_INFO_URL = "https://open.ys7.com/api/lapp/device/info";
}
/**
* @ProjectName: aila
* @Package: com.aila.fluorite.common
* @ClassName: AuthTool
* @Author: dujiayu
* @Description: 萤石授权
* @Date: 2022/1/18 11:54
* @Version: 1.0
*/
@Slf4j
@Component
public class FluorAuthTool {
@Autowired
private RestTemplate restTemplate;
@Autowired
private RedisCache redisCache;
/**
* 获取萤石开放平台AccessToken
*
* @param appKey
* @param appSecret
* @return
*/
public String getAccessToken(String appKey, String appSecret) throws FluorException {
String accessToken = redisCache.getCacheObject(FluorConstant.REDIS_FLUOR_ACCESSTOKEN_KEY);
if (StringUtils.isNotEmpty(accessToken)) {
return accessToken;
}
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/x-www-form-urlencoded");
headers.set("Host", "open.ys7.com");
log.info("获取萤石AccessToken入参======" + "appKey:" + appKey + " appSecret:" + appSecret);
HttpEntity<String> request = new HttpEntity<String>(headers);
AccessTokenDTO response = null;
try {
String url = FluorConstant.GETACCESSTOKEN_URL + "?appKey=" + appKey + "&appSecret=" + appSecret;
response = restTemplate.postForObject(url, request, AccessTokenDTO.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString(), AccessTokenDTO.class);
}
log.info("获取萤石AccessToken返回信息======" + JSON.toJSONString(response));
if (FluorConstant.REQUEST_SUCCEESS.equals(response.getCode())) {
accessToken = response.getData().getString("accessToken");
Long expireTime = response.getData().getLong("expireTime");
redisCache.setCacheObject(FluorConstant.REDIS_FLUOR_ACCESSTOKEN_KEY, accessToken, expireTime, TimeUnit.MILLISECONDS);
} else {
throw new FluorException(response.getMsg(), Integer.parseInt(response.getCode()));
}
return accessToken;
}
/**
* 直接获取token
* @param appKey
* @param appSecret
* @return
* @throws FluorException
*/
public String getDirectAccessToken(String appKey, String appSecret) throws FluorException {
String accessToken = "";
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/x-www-form-urlencoded");
headers.set("Host", "open.ys7.com");
log.info("获取萤石AccessToken入参======" + "appKey:" + appKey + " appSecret:" + appSecret);
HttpEntity<String> request = new HttpEntity<String>(headers);
AccessTokenDTO response = null;
try {
String url = FluorConstant.GETACCESSTOKEN_URL + "?appKey=" + appKey + "&appSecret=" + appSecret;
response = restTemplate.postForObject(url, request, AccessTokenDTO.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString(), AccessTokenDTO.class);
}
log.info("获取萤石AccessToken返回信息======" + JSON.toJSONString(response));
if (FluorConstant.REQUEST_SUCCEESS.equals(response.getCode())) {
accessToken = response.getData().getString("accessToken");
Long expireTime = response.getData().getLong("expireTime");
redisCache.setCacheObject(FluorConstant.REDIS_FLUOR_ACCESSTOKEN_KEY, accessToken, expireTime, TimeUnit.MILLISECONDS);
} else {
throw new FluorException(response.getMsg(), Integer.parseInt(response.getCode()));
}
return accessToken;
}
/**
* 获取萤石IOT AccessToken(非物联网用不上)
*
* @param accessToken
* @return
*/
public String getEZAccessToken(String accessToken) {
JSONObject object = new JSONObject();
object.put("accessToken", accessToken);
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json");
log.info("获取萤石IOT AccessToken======" + object.toJSONString());
HttpEntity<String> request = new HttpEntity<String>(object.toJSONString(),headers);
JSONObject response = null;
try {
response = restTemplate.postForObject(FluorConstant.GETEZACCESSTOKEN_URL,
request, JSONObject.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString());
}
return response.toJSONString();
}
}
/**
* @ProjectName: aila
* @Package: com.aila.fluorite.camera
* @ClassName: CameraTool
* @Author: dujiayu
* @Description: 萤石管理相关接口
* @Date: 2022/1/18 11:47
* @Version: 1.0
*/
@Slf4j
@Component
public class FluorDeviceManageTool {
@Autowired
private RestTemplate restTemplate;
@Autowired
private FluorAuthTool fluorAuthTool;
/**
* 生成公用的请求头
*
* @return
*/
private HttpEntity<String> getHttpEntity() {
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/x-www-form-urlencoded");
headers.set("Host", "open.ys7.com");
HttpEntity<String> request = new HttpEntity<String>(headers);
return request;
}
/**
* 添加设备
*
* @param accessToken 授权过程获取的access_token
* @param deviceSerial 设备序列号,存在英文字母的设备序列号,字母需为大写
* @param validateCode 设备验证码
* @return
* @throws FluorException
*/
public boolean addDecvice(String accessToken, String deviceSerial, String validateCode) throws FluorException {
log.info("添加设备入参======" + "accessToken:" + accessToken + " deviceSerial:" + deviceSerial + "validateCode:" + validateCode);
HttpEntity<String> request = this.getHttpEntity();
FluorResponseDTO response = null;
try {
String url = FluorConstant.DEVICE_ADD_URL + "?accessToken=" + accessToken + "&deviceSerial=" + deviceSerial + "&validateCode=" + validateCode;
response = restTemplate.postForObject(url, request, FluorResponseDTO.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString(), FluorResponseDTO.class);
}
log.info("添加设备返回信息======" + JSON.toJSONString(response));
if (FluorConstant.TOKEN_EXPIRED.equals(response.getCode())) {
accessToken = fluorAuthTool.getDirectAccessToken(FluorConstant.APP_KEY, FluorConstant.SECRET);
return addDecvice(accessToken, deviceSerial, validateCode);
}
if (!FluorConstant.REQUEST_SUCCEESS.equals(response.getCode())) {
throw new FluorException(response.getMsg(), Integer.parseInt(response.getCode()));
}
return true;
}
/**
* 删除设备
*
* @param accessToken 授权过程获取的access_token
* @param deviceSerial 设备序列号,存在英文字母的设备序列号,字母需为大写
* @return
* @throws FluorException
*/
public boolean deleteDecvice(String accessToken, String deviceSerial) throws FluorException {
log.info("删除设备入参======" + "accessToken:" + accessToken + " deviceSerial:" + deviceSerial);
HttpEntity<String> request = this.getHttpEntity();
FluorResponseDTO response = null;
try {
String url = FluorConstant.DEVICE_DELETE_URL + "?accessToken=" + accessToken + "&deviceSerial=" + deviceSerial;
response = restTemplate.postForObject(url, request, FluorResponseDTO.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString(), FluorResponseDTO.class);
}
log.info("删除设备返回信息======" + JSON.toJSONString(response));
if (FluorConstant.TOKEN_EXPIRED.equals(response.getCode())) {
accessToken = fluorAuthTool.getDirectAccessToken(FluorConstant.APP_KEY, FluorConstant.SECRET);
return deleteDecvice(accessToken, deviceSerial);
}
if (!FluorConstant.REQUEST_SUCCEESS.equals(response.getCode())) {
throw new FluorException(response.getMsg(), Integer.parseInt(response.getCode()));
}
return true;
}
/**
* 修改设备名称
*
* @param accessToken 授权过程获取的access_token
* @param deviceSerial 设备序列号,存在英文字母的设备序列号,字母需为大写
* @param deviceName 设备名称,长度不大于50字节,不能包含特殊字符
* @return
* @throws FluorException
*/
public boolean updateDecvice(String accessToken, String deviceSerial, String deviceName) throws FluorException {
log.info("修改设备名称入参======" + "accessToken:" + accessToken + " deviceSerial:" + deviceSerial + "deviceName:" + deviceName);
HttpEntity<String> request = this.getHttpEntity();
FluorResponseDTO response = null;
try {
String url = FluorConstant.DEVICE_UPDATE_URL + "?accessToken=" + accessToken + "&deviceSerial=" + deviceSerial + "&deviceName=" + deviceName;
response = restTemplate.postForObject(url, request, FluorResponseDTO.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString(), FluorResponseDTO.class);
}
log.info("修改设备名称返回信息======" + JSON.toJSONString(response));
if (FluorConstant.TOKEN_EXPIRED.equals(response.getCode())) {
accessToken = fluorAuthTool.getDirectAccessToken(FluorConstant.APP_KEY, FluorConstant.SECRET);
return updateDecvice(accessToken, deviceSerial, deviceName);
}
if (!FluorConstant.REQUEST_SUCCEESS.equals(response.getCode())) {
throw new FluorException(response.getMsg(), Integer.parseInt(response.getCode()));
}
return true;
}
/**
* 设备抓拍图片
* 设备抓图能力有限,请勿频繁调用,建议每个摄像头调用的间隔4s以上。
* 抓拍后的图片路径,图片保存有效期为2小时
*
* @param accessToken 授权过程获取的access_token
* @param deviceSerial 设备序列号,存在英文字母的设备序列号,字母需为大写
* @param channelNo 通道号,IPC设备填写1
* @return
* @throws FluorException
*/
public FluorCaptureDeviceDTO captureDevice(String accessToken, String deviceSerial, Integer channelNo) throws FluorException {
log.info("设备抓拍图片入参======" + "accessToken:" + accessToken + " deviceSerial:" + deviceSerial + "channelNo:" + channelNo);
HttpEntity<String> request = this.getHttpEntity();
FluorResponseDTO response = null;
try {
String url = FluorConstant.DEVICE_CAPTURE_URL + "?accessToken=" + accessToken + "&deviceSerial=" + deviceSerial + "&channelNo=" + channelNo;
response = restTemplate.postForObject(url, request, FluorResponseDTO.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString(), FluorResponseDTO.class);
}
log.info("设备抓拍图片返回信息======" + JSON.toJSONString(response));
if (!FluorConstant.REQUEST_SUCCEESS.equals(response.getCode())) {
throw new FluorException(response.getMsg(), Integer.parseInt(response.getCode()));
}
String jsonData = response.getData().toJSONString();
FluorCaptureDeviceDTO data = JSONObject.parseObject(jsonData,FluorCaptureDeviceDTO.class);
return data;
}
/**
* 修改通道名称
*
* @param accessToken 授权过程获取的access_token
* @param deviceSerial 设备序列号,存在英文字母的设备序列号,字母需为大写
* @param name 通道名称,长度不大于50字节,不能包含特殊字符
* @param channelNo 非必选参数,不为空表示修改指定通道名称,为空表示修改通道1名称
* @return
* @throws FluorException
*/
public boolean updatePassageName(String accessToken, String deviceSerial, String name, Integer channelNo) throws FluorException {
log.info("修改通道名称入参======" + "accessToken:" + accessToken + " deviceSerial:" + deviceSerial + "name:" + name+ "channelNo:" + channelNo);
HttpEntity<String> request = this.getHttpEntity();
FluorResponseDTO response = null;
try {
String url = FluorConstant.DEVICE_CAMERAUPDATE_URL + "?accessToken=" + accessToken + "&deviceSerial=" + deviceSerial + "&name=" + name+ "&channelNo=" + channelNo;
response = restTemplate.postForObject(url, request, FluorResponseDTO.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString(), FluorResponseDTO.class);
}
log.info("修改通道名称返回信息======" + JSON.toJSONString(response));
if (!FluorConstant.REQUEST_SUCCEESS.equals(response.getCode())) {
throw new FluorException(response.getMsg(), Integer.parseInt(response.getCode()));
}
return true;
}
}
/**
* @ProjectName: aila
* @Package: com.aila.fluor.device
* @ClassName: FluorDeviceQueryTool
* @Author: dujiayu
* @Description: 萤石查询相关接口
* @Date: 2022/1/19 15:45
* @Version: 1.0
*/
@Slf4j
@Component
public class FluorDeviceQueryTool {
@Autowired
private RestTemplate restTemplate;
@Autowired
private FluorAuthTool fluorAuthTool;
/**
* 生成公用的请求头
*
* @return
*/
private HttpEntity<String> getHttpEntity() {
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/x-www-form-urlencoded");
headers.set("Host", "open.ys7.com");
HttpEntity<String> request = new HttpEntity<String>(headers);
return request;
}
/**
* 获取设备列表
*
* @param accessToken 授权过程获取的access_token
* @return
* @throws FluorException
*/
public DeviceListDTO getDeviceList(String accessToken) throws FluorException {
return this.getDeviceList(accessToken, null, null);
}
/**
* 获取设备列表
*
* @param accessToken 授权过程获取的access_token
* @param pageStart 分页起始页,从0开始
* @param pageSize 分页大小,默认为10,最大为50
* @return
* @throws FluorException
*/
public DeviceListDTO getDeviceList(String accessToken, Integer pageStart, Integer pageSize) throws FluorException {
pageStart = null == pageStart ? 0 : pageStart;
pageSize = null == pageSize ? 10 : pageSize;
HttpEntity<String> request = this.getHttpEntity();
log.info("获取设备列表入参======" + "accessToken:" + accessToken + " pageStart:" + pageStart + "pageSize:" + pageSize);
DeviceListDTO response = null;
try {
String url = FluorConstant.DEVICE_SELECT_URL + "?accessToken=" + accessToken + "&pageStart=" + pageStart + "&pageSize=" + pageSize;
response = restTemplate.postForObject(url, request, DeviceListDTO.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString(), DeviceListDTO.class);
}
log.info("获取设备列表返回信息======" + JSON.toJSONString(response));
if (FluorConstant.TOKEN_EXPIRED.equals(response.getCode())) {
accessToken = fluorAuthTool.getDirectAccessToken(FluorConstant.APP_KEY, FluorConstant.SECRET);
return getDeviceList(accessToken, pageStart, pageSize);
}
if (!FluorConstant.REQUEST_SUCCEESS.equals(response.getCode())) {
throw new FluorException(response.getMsg(), Integer.parseInt(response.getCode()));
}
return response;
}
/**
* 获取单个设备信息
*
* @param accessToken 授权过程获取的access_token
* @param deviceSerial 设备序列号,存在英文字母的设备序列号,字母需为大写
*/
public DeviceInfoResDTO getDeviceInfo(String accessToken, String deviceSerial) throws FluorException {
HttpEntity<String> request = this.getHttpEntity();
log.info("获取单个设备信息入参======" + "accessToken:" + accessToken + " deviceSerial:" + deviceSerial);
FluorResponseDTO response = null;
try {
String url = FluorConstant.DEVICE_INFO_URL + "?accessToken=" + accessToken + "&deviceSerial=" + deviceSerial;
response = restTemplate.postForObject(url, request, FluorResponseDTO.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString(), FluorResponseDTO.class);
}
log.info("获取单个设备信息返回信息======" + JSON.toJSONString(response));
if (FluorConstant.TOKEN_EXPIRED.equals(response.getCode())) {
accessToken = fluorAuthTool.getDirectAccessToken(FluorConstant.APP_KEY, FluorConstant.SECRET);
return getDeviceInfo(accessToken, deviceSerial);
}
if (!FluorConstant.REQUEST_SUCCEESS.equals(response.getCode())) {
throw new FluorException(response.getMsg(), Integer.parseInt(response.getCode()));
}
String jsonData = response.getData().toJSONString();
DeviceInfoResDTO data = JSONObject.parseObject(jsonData, DeviceInfoResDTO.class);
return data;
}
//TODO 获取摄像头列表
//TODO 获取设备状态信息
}
/**
* @ProjectName: aila
* @Package: com.aila.fluor.dto
* @ClassName: AccessTokenDTO
* @Author: dujiayu
* @Description: AccessToken返回参数
* @Date: 2022/1/18 13:57
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AccessTokenDTO {
private JSONObject data;
private String code;
private String msg;
}
/**
* @ProjectName: aila
* @Package: com.aila.fluor.dto
* @ClassName: DeviceInfoResDTO
* @Author: dujiayu
* @Description: 设备信息详情返回参数
* @Date: 2022/1/19 16:23
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeviceInfoResDTO {
/**
* 设备序列号
*/
private String deviceSerial;
/**
* 设备名称
*/
private String deviceName;
/**
* 设备型号,如CS-C2S-21WPFR-WX
*/
private String model;
/**
* 在线状态:0-不在线,1-在线
*/
private Integer status;
/**
* 具有防护能力的设备布撤防状态:0-睡眠,8-在家,16-外出,普通IPC布撤防状态:0-撤防,1-布防
*/
private Integer defence;
/**
* 是否加密:0-不加密,1-加密
*/
private Integer isEncrypt;
/**
* 告警声音模式:0-短叫,1-长叫,2-静音
*/
private Integer alarmSoundMode;
/**
* 设备下线是否通知:0-不通知 1-通知
*/
private Integer offlineNotify;
/**
* 设备大类
*/
private String category;
/**
* 网络类型,如有线连接wire
*/
private String netType;
/**
* 信号强度(%)
*/
private String signal;
}
/**
* @ProjectName: aila
* @Package: com.aila.fluor.dto
* @ClassName: DeviceListDTO
* @Author: dujiayu
* @Description: 获取设备列表
* @Date: 2022/1/19 10:21
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeviceListDTO {
/**
* 分页信息对象
*/
private Page page;
/**
* 设备数据列表
*/
private List<DeviceListItemDTO> data;
/**
* 状态码
*/
private String code;
/**
* 状态信息
*/
private String msg;
}
/**
* @ProjectName: aila
* @Package: com.aila.fluor.dto
* @ClassName: DeviceListItem
* @Author: dujiayu
* @Description: 设备列表子项数据
* @Date: 2022/1/19 10:28
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeviceListItemDTO {
/**
* 设备序列号,存在英文字母的设备序列号,字母需为大写
*/
private String deviceSerial;
/**
* 设备名称
*/
private String deviceName;
/**
* 设备类型
*/
private String deviceType;
/**
* 在线状态:0-不在线,1-在线
*/
private Integer status;
/**
* 具有防护能力的设备布撤防状态:0-睡眠,8-在家,16-外出,普通IPC布撤防状态:0-撤防,1-布防
*/
private Integer defence;
/**
* 设备版本号
*/
private String deviceVersion;
}
/**
* @ProjectName: aila
* @Package: com.aila.fluor.dto
* @ClassName: FluorCaptureDeviceDTO
* @Author: dujiayu
* @Description: 设备抓拍
* @Date: 2022/1/19 14:53
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FluorCaptureDeviceDTO {
/**
* 图片地址
*/
private String picUrl;
}
/**
* @ProjectName: aila
* @Package: com.aila.fluor.dto
* @ClassName: FluorResponseDTO
* @Author: dujiayu
* @Description: 萤石返回基本参数
* @Date: 2022/1/19 13:52
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FluorResponseDTO {
/**
* 返回码
*/
private String code;
/**
* 返回消息
*/
private String msg;
/**
* 数据对象
*/
private JSONObject data;
}
/**
* @ProjectName: aila
* @Package: com.aila.fluor.dto
* @ClassName: Page
* @Author: dujiayu
* @Description: 分页数据
* @Date: 2022/1/19 10:22
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Page {
/**
* 总数
*/
private Integer total;
/**
* 当前页
*/
private Integer page;
/**
* 分页大小
*/
private Integer size;
}
/**
* @ProjectName: aila
* @Package: com.aila.fluor.exception
* @ClassName: FluorException
* @Author: dujiayu
* @Description: 萤石抛出异常
* @Date: 2022/1/19 10:51
* @Version: 1.0
*/
public class FluorException extends Exception {
private static final long serialVersionUID = 1L;
private Integer code;
private final String message;
public FluorException(String message) {
this.message = message;
}
public FluorException(String message, Integer code) {
this.message = message;
this.code = code;
}
public FluorException(String message, Throwable e) {
super(message, e);
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public Integer getCode() {
return code;
}
}