- reolink: check and fix netData (#1934)

- reolink: restrict homehub streams to RTSP

Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
This commit is contained in:
apocaliss92
2025-11-27 17:42:35 +01:00
committed by GitHub
parent fe94472282
commit 70c46f9894
2 changed files with 134 additions and 2 deletions

View File

@@ -7,7 +7,7 @@ import { OnvifCameraAPI, OnvifEvent, connectCameraAPI } from './onvif-api';
import { listenEvents } from './onvif-events';
import { OnvifIntercom } from './onvif-intercom';
import { DevInfo } from './probe';
import { AIState, Enc, isDeviceNvr, ReolinkCameraClient } from './reolink-api';
import { AIState, Enc, isDeviceHomeHub, isDeviceNvr, ReolinkCameraClient } from './reolink-api';
class ReolinkCameraSiren extends ScryptedDeviceBase implements OnOff {
sirenTimeout: NodeJS.Timeout;
@@ -237,6 +237,7 @@ class ReolinkCamera extends RtspSmartCamera implements Camera, DeviceProvider, R
await this.updateAbilities();
await this.updateDevice();
await this.reportDevices();
await this.checkNetData();
this.startDevicesStatesPolling();
})()
.catch(e => {
@@ -464,6 +465,26 @@ class ReolinkCamera extends RtspSmartCamera implements Camera, DeviceProvider, R
return batteryConfigVer > 0;
}
hasRtsp() {
const rtspAbility = this.storageSettings.values.abilities?.value?.Ability?.supportRtspEnable;
return rtspAbility && rtspAbility?.ver !== 0;
}
hasRtmp() {
const rtmpAbility = this.storageSettings.values.abilities?.value?.Ability?.supportRtmpEnable;
return rtmpAbility && rtmpAbility?.ver !== 0;
}
hasOnvif() {
const onvifAbility = this.storageSettings.values.abilities?.value?.Ability?.supportOnvifEnable;
return onvifAbility && onvifAbility?.ver !== 0;
}
hasHttps() {
const httpsAbility = this.storageSettings.values.abilities?.value?.Ability?.supportHttpsEnable;
return httpsAbility && httpsAbility?.ver !== 0;
}
async updateDevice() {
const interfaces = this.provider.getInterfaces();
let type = ScryptedDeviceType.Camera;
@@ -844,7 +865,9 @@ class ReolinkCamera extends RtspSmartCamera implements Camera, DeviceProvider, R
// anecdotally, encoders of type h265 do not have a working RTMP main stream.
const mainEncType = this.storageSettings.values.abilities?.value?.Ability?.abilityChn?.[rtspChannel]?.mainEncType?.ver;
if (live === 2) {
if (isDeviceHomeHub(deviceInfo)) {
streams.push(...[rtspMain, rtspSub]);
} else if (live === 2) {
if (mainEncType === 1) {
streams.push(rtmpSub, rtspMain, rtspSub);
}
@@ -1039,6 +1062,53 @@ class ReolinkCamera extends RtspSmartCamera implements Camera, DeviceProvider, R
});
}
async checkNetData() {
try {
const api = this.getClientWithToken();
const { netData } = await api.getNetData();
this.console.log('netData', JSON.stringify(netData));
const deviceInfo = this.storageSettings.values.deviceInfo;
const isHomeHub = isDeviceHomeHub(deviceInfo);
const shouldDisableHttps = this.hasHttps() ? netData.httpsEnable === 1 : false;
const shouldEnableRtmp = this.hasRtmp() ? (!isHomeHub && netData.rtmpEnable === 0) : false;
const shouldDisableRtmp = this.hasRtmp() ? (isHomeHub && netData.rtmpEnable === 1) : false;
const shouldEnableRtsp = this.hasRtsp() ? netData.rtspEnable === 0 : false;
const shouldEnableOnvif = this.hasOnvif() ? netData.onvifEnable === 0 : false;
this.console.log(`NetData checks: shouldDisableHttps: ${shouldDisableHttps}, shouldEnableRtmp: ${shouldEnableRtmp}, shouldEnableRtsp: ${shouldEnableRtsp}, shouldEnableOnvif: ${shouldEnableOnvif}, shouldDisableRtmp: ${shouldDisableRtmp}`);
if (shouldDisableHttps || shouldEnableRtmp || shouldEnableRtsp || shouldEnableOnvif || shouldDisableRtmp) {
const newNetData = {
...netData
};
if (shouldDisableHttps) {
newNetData.httpsEnable = 0;
}
if (shouldEnableRtmp) {
newNetData.rtmpEnable = 1;
}
if (shouldDisableRtmp) {
newNetData.rtmpEnable = 0;
}
if (shouldEnableRtsp) {
newNetData.rtspEnable = 1;
}
if (shouldEnableOnvif) {
newNetData.onvifEnable = 1;
}
this.console.log(`Fixing netdata settings: ${JSON.stringify(newNetData)}`);
await api.setNetData(newNetData);
}
} catch (e) {
this.console.error('Error in pollDeviceStates', e);
}
}
async getDevice(nativeId: string): Promise<any> {
if (nativeId.endsWith('-siren')) {
this.siren ||= new ReolinkCameraSiren(this, nativeId);

View File

@@ -75,7 +75,22 @@ export interface PtzPreset {
name: string;
}
export interface NetData {
httpEnable: 1 | 0,
httpPort: number,
httpsEnable: 1 | 0,
httpsPort: number,
mediaPort: number,
onvifEnable: 1 | 0,
onvifPort: number,
rtmpEnable: 1 | 0,
rtmpPort: number,
rtspEnable: 1 | 0,
rtspPort: number
}
export const isDeviceNvr = (deviceInfo: DevInfo) => ['HOMEHUB', 'NVR', 'NVR_WIFI'].includes(deviceInfo.exactType);
export const isDeviceHomeHub = (deviceInfo: DevInfo) => deviceInfo.exactType === 'HOMEHUB';
export class ReolinkCameraClient {
credential: AuthFetchCredentialState;
@@ -767,4 +782,51 @@ export class ReolinkCameraClient {
isWifi
};
}
async getNetData() {
const url = new URL(`http://${this.host}/api.cgi`);
const body = [{
cmd: 'GetNetPort',
action: 1,
}];
const response = await this.requestWithLogin({
url,
method: 'POST',
responseType: 'json',
}, this.createReadable(body));
const error = response.body?.[0]?.error;
if (error) {
this.console.error('error during call to getWhiteLedState', JSON.stringify(body), error);
}
return {
netData: response.body?.[0]?.value?.NetPort as NetData,
};
}
async setNetData(netData: NetData) {
const url = new URL(`http://${this.host}/api.cgi`);
const body = [{
cmd: 'SetNetPort',
param: {
NetPort: netData
}
}];
const response = await this.requestWithLogin({
url,
method: 'POST',
responseType: 'json',
}, this.createReadable(body));
const error = response.body?.[0]?.error;
if (error) {
this.console.error('error during call to setNetData', JSON.stringify(body), error);
}
}
}