1313# limitations under the License.
1414
1515from re import match , compile
16+ from ipaddress import IPv4Network
1617import asyncio
1718from asyncio import Queue , CancelledError , QueueEmpty
1819from copy import deepcopy
2425from typing import TYPE_CHECKING , Tuple , Any
2526from concurrent .futures import TimeoutError
2627
27- from thingsboard_gateway .connectors .bacnet .constants import SUPPORTED_OBJECTS_TYPES
28+ from thingsboard_gateway .connectors .bacnet .constants import SUPPORTED_OBJECTS_TYPES , ALLOWED_APDU
2829from typing import TYPE_CHECKING
2930from ast import literal_eval
3031
@@ -206,6 +207,10 @@ async def __rescan_devices(self):
206207 await asyncio .sleep (.1 )
207208
208209 async def __start (self ):
210+ if not self .__is_valid_application_device_section ():
211+ self .__log .error ('Can not start connector due to invalid application section in config.' )
212+ return
213+
209214 if self .__config .get ('foreignDevice' , {}).get ('address' , '' ):
210215 self .__application = Application (DeviceObjectConfig (
211216 self .__config ['application' ]), self .__handle_indication , self .__log ,
@@ -226,6 +231,55 @@ async def __start(self):
226231 self .indication_callback (),
227232 self .__application .confirmation_handler ())
228233
234+ def __is_valid_application_device_section (self ) -> bool :
235+ app = self .__config .get ('application' )
236+ if not isinstance (app , dict ):
237+ self .__log .error ("Missing or invalid 'application' section in config." )
238+ return False
239+
240+ host = app .get ('host' )
241+ if not host :
242+ self .__log .error ("Missing IPv4 address: 'application.address' (or 'application.host')." )
243+ return False
244+ try :
245+ IPv4Address (str (host ))
246+ except Exception :
247+ self .__log .error ("Invalid IPv4 address in application section: %s" , host )
248+ return False
249+
250+ port = app .get ('port' )
251+ if not (1 <= port <= 65535 ):
252+ self .__log .error (
253+ "The port inside application section must be in range [1, 65535], but got %d." ,
254+ port
255+ )
256+ return False
257+
258+ apdu = app .get ('maxApduLengthAccepted' , 1476 )
259+ if apdu not in ALLOWED_APDU :
260+ self .__log .warning (
261+ "Unsupported value for 'maxApduLengthAccepted': %d. Allowed values are %s. Using default - 1476." ,
262+ apdu , ALLOWED_APDU
263+ )
264+ app ['maxApduLengthAccepted' ] = 1476
265+
266+ mask = app .get ('mask' , "24" )
267+ try :
268+ if mask .isdigit () and not (0 <= int (mask ) <= 32 ):
269+ self .__log .warning (
270+ "The mask inside application section must be in range [0, 32], but got %s., using default - 24" ,
271+ mask )
272+ app ['mask' ] = "24"
273+ return True
274+ else :
275+ IPv4Network (f"{ host } /{ mask } " )
276+ return True
277+ except Exception :
278+ app ['mask' ] = "24"
279+ self .__log .warning ("Invalid subnet mask inside application section : %s using default - 24" , mask )
280+
281+ return True
282+
229283 def __handle_indication (self , apdu ):
230284 self .__indication_queue .put_nowait (apdu )
231285
0 commit comments