@@ -9,7 +9,12 @@ import type {
99import type { EventLogData } from '@/types/opendtu/eventlog' ;
1010import type { GridProfileData } from '@/types/opendtu/gridprofile' ;
1111import type { InverterDeviceData } from '@/types/opendtu/inverterDevice' ;
12- import type { NetworkSettings } from '@/types/opendtu/settings' ;
12+ import type {
13+ NetworkSettings ,
14+ NTPSettings ,
15+ NTPTime ,
16+ TimezoneData ,
17+ } from '@/types/opendtu/settings' ;
1318import type { InverterItem } from '@/types/opendtu/state' ;
1419import { DeviceState } from '@/types/opendtu/state' ;
1520import type {
@@ -105,9 +110,14 @@ class OpenDtuApi {
105110 inverterSerial : InverterSerial ,
106111 ) => void )
107112 | null = null ;
113+
114+ // settings
108115 private onNetworkSettingsHandler :
109116 | ( ( data : NetworkSettings , index : Index ) => void )
110117 | null = null ;
118+ private onNtpSettingsHandler :
119+ | ( ( data : NTPSettings , index : Index ) => void )
120+ | null = null ;
111121
112122 private ws : WebSocket | null = null ;
113123 // communication
@@ -329,6 +339,18 @@ class OpenDtuApi {
329339 this . onNetworkSettingsHandler = null ;
330340 }
331341
342+ public registerOnNtpSettingsHandler (
343+ handler : ( data : NTPSettings , index : Index ) => void ,
344+ ) : void {
345+ log . debug ( 'OpenDtuApi.registerOnNtpSettingsHandler()' ) ;
346+ this . onNtpSettingsHandler = handler ;
347+ }
348+
349+ public unregisterOnNtpSettingsHandler ( ) : void {
350+ log . debug ( 'OpenDtuApi.unregisterOnNtpSettingsHandler()' ) ;
351+ this . onNtpSettingsHandler = null ;
352+ }
353+
332354 public async getSystemStatusFromUrl (
333355 url : URL ,
334356 ) : Promise < GetSystemStatusReturn > {
@@ -1238,6 +1260,147 @@ class OpenDtuApi {
12381260 return res . status === 200 && parsed . type === 'success' ;
12391261 }
12401262
1263+ public async getNTPConfig ( ) : Promise < NTPSettings | null > {
1264+ if ( ! this . baseUrl ) {
1265+ log . error ( 'getNTPConfig' , 'no base url' ) ;
1266+ return null ;
1267+ }
1268+
1269+ const res = await this . makeAuthenticatedRequest ( '/api/ntp/config' , 'GET' ) ;
1270+
1271+ if ( ! res ) {
1272+ log . error ( 'getNNTPConfig' , 'no response' ) ;
1273+ return null ;
1274+ }
1275+
1276+ if ( res . status === 200 ) {
1277+ const json = await res . json ( ) ;
1278+
1279+ if ( this . onNtpSettingsHandler && this . index !== null ) {
1280+ this . onNtpSettingsHandler ( json , this . index ) ;
1281+ }
1282+
1283+ log . debug ( 'getNTPConfig' , 'success' ) ;
1284+
1285+ return json ;
1286+ }
1287+
1288+ log . error ( 'getNTPConfig' , 'invalid status' , res . status ) ;
1289+
1290+ return null ;
1291+ }
1292+
1293+ public async setNTPConfig ( config : NTPSettings ) : Promise < boolean | null > {
1294+ if ( ! this . baseUrl ) {
1295+ log . error ( 'setNTPConfig' , 'no base url' ) ;
1296+ return null ;
1297+ }
1298+
1299+ const formData = new FormData ( ) ;
1300+ formData . append ( 'data' , JSON . stringify ( config ) ) ;
1301+
1302+ const res = await this . makeAuthenticatedRequest ( '/api/ntp/config' , 'POST' , {
1303+ body : formData ,
1304+ } ) ;
1305+
1306+ if ( ! res ) {
1307+ log . error ( 'setNTPConfig' , 'no response' ) ;
1308+ return null ;
1309+ }
1310+
1311+ const parsed = await res . json ( ) ;
1312+
1313+ log . debug ( 'setNTPConfig' , 'success' , {
1314+ status : res . status ,
1315+ parsed,
1316+ } ) ;
1317+
1318+ return res . status === 200 && parsed . type === 'success' ;
1319+ }
1320+
1321+ public async fetchTimezones ( ) : Promise < TimezoneData | null > {
1322+ // fetch /zones.json
1323+ if ( ! this . baseUrl ) {
1324+ log . error ( 'fetchTimezones' , 'no base url' ) ;
1325+ return null ;
1326+ }
1327+
1328+ const res = await fetch ( `${ this . baseUrl } /zones.json` ) . catch ( ( ) => null ) ;
1329+
1330+ if ( ! res ) {
1331+ log . error ( 'fetchTimezones' , 'no response' ) ;
1332+ return null ;
1333+ }
1334+
1335+ if ( res . status === 200 ) {
1336+ const json = await res . json ( ) ;
1337+
1338+ log . debug ( 'fetchTimezones' , 'success' ) ;
1339+
1340+ return json ;
1341+ }
1342+
1343+ log . error ( 'fetchTimezones' , 'invalid status' , res . status ) ;
1344+
1345+ return null ;
1346+ }
1347+
1348+ public async getNTPTime ( ) : Promise < NTPTime | null > {
1349+ if ( ! this . baseUrl ) {
1350+ log . error ( 'getNTPTime' , 'no base url' ) ;
1351+ return null ;
1352+ }
1353+
1354+ const res = await this . makeAuthenticatedRequest ( '/api/ntp/time' , 'GET' ) ;
1355+
1356+ if ( ! res ) {
1357+ log . error ( 'getNTPTime' , 'no response' ) ;
1358+ return null ;
1359+ }
1360+
1361+ if ( res . status === 200 ) {
1362+ const json = await res . json ( ) ;
1363+
1364+ log . debug ( 'getNTPTime' , 'success' ) ;
1365+
1366+ return json ;
1367+ }
1368+
1369+ log . error ( 'getNTPTime' , 'invalid status' , res . status ) ;
1370+
1371+ return null ;
1372+ }
1373+
1374+ public async setNTPTime (
1375+ config : Omit < NTPTime , 'ntp_status' > ,
1376+ ) : Promise < boolean | null > {
1377+ if ( ! this . baseUrl ) {
1378+ log . error ( 'setNTPTime' , 'no base url' ) ;
1379+ return null ;
1380+ }
1381+
1382+ const formData = new FormData ( ) ;
1383+ formData . append ( 'data' , JSON . stringify ( config ) ) ;
1384+
1385+ const res = await this . makeAuthenticatedRequest ( '/api/ntp/time' , 'POST' , {
1386+ body : formData ,
1387+ } ) ;
1388+
1389+ if ( ! res ) {
1390+ log . error ( 'setNTPTime' , 'no response' ) ;
1391+ return null ;
1392+ }
1393+
1394+ const parsed = await res . json ( ) ;
1395+
1396+ log . debug ( 'setNTPTime' , 'success' , {
1397+ status : res . status ,
1398+ parsed,
1399+ } ) ;
1400+
1401+ return res . status === 200 && parsed . type === 'success' ;
1402+ }
1403+
12411404 public async makeAuthenticatedRequest (
12421405 route : string ,
12431406 method : 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'PATCH' ,
0 commit comments