How to use _client method in localstack

Best Python code snippet using localstack_python

Galil_DMC_22x0_NgClient.py

Source:Galil_DMC_22x0_NgClient.py Github

copy

Full Screen

1#!/usr/bin/env python32# -*- coding: utf-8 -*-3# +4# import(s)5# -6from astropy.time import Time7from datetime import datetime8from datetime import timedelta9import argparse10import math11import os12import random13import socket14# +15# __doc__16# -17__doc__ = """ python3 Galil_DMC_22x0_NgClient.py --help """18# +19# constant(s)20# -21BOK_NG_HELP = os.path.abspath(os.path.expanduser(os.path.join(os.getenv("BOK_GALIL_DOCS", os.getcwd()), 'bok_ng_commands.txt')))22BOK_NG_FALSE = [0, '0', 'false', False]23BOK_NG_GFILTER_SLOTS = [1, 2, 3, 4, 5, 6]24BOK_NG_HOST = "10.30.1.2"25BOK_NG_IFILTER_SLOTS = [0, 1, 2, 3, 4, 5]26BOK_NG_INSTRUMENT = "90PRIME"27BOK_NG_PORT = 575028BOK_NG_STRING = 102429BOK_NG_TELESCOPE = "BOK"30BOK_NG_TIMEOUT = 120.031BOK_NG_TRUE = [1, '1', 'true', True]32BOK_COLORS = ['black', 'blue', 'cyan', 'green', 'yellow', 'magenta', 'red']33# +34# initialize35# -36random.seed(os.getpid())37# +38# function: pdh()39# -40def pdh(msg: str = '', color: str = BOK_COLORS[0], height: int = 1):41 """ print double (or single) height and in color """42 # check input(s)43 color = color.lower() if color.lower() in BOK_COLORS else BOK_COLORS[0].lower()44 height = height if (1 <= height <= 2) else 145 # output46 if msg != '':47 # single height48 if height == 1:49 if color == 'red':50 print(f"\033[0;31m{msg}\033[0m")51 elif color == 'green':52 print(f"\033[0;32m{msg}\033[0m")53 elif color == 'yellow':54 print(f"\033[0;33m{msg}\033[0m")55 elif color == 'blue':56 print(f"\033[0;34m{msg}\033[0m")57 elif color == 'magenta':58 print(f"\033[0;35m{msg}\033[0m")59 elif color == 'cyan':60 print(f"\033[0;36m{msg}\033[0m")61 else:62 print(f"\033[0;30m{msg}\033[0m")63 # double height64 elif height == 2:65 if color == 'red':66 print(f"\033[0;31m\033#3{msg}\n\033#4{msg}\033[0m")67 elif color == 'green':68 print(f"\033[0;32m\033#3{msg}\n\033#4{msg}\033[0m")69 elif color == 'yellow':70 print(f"\033[0;33m\033#3{msg}\n\033#4{msg}\033[0m")71 elif color == 'blue':72 print(f"\033[0;34m\033#3{msg}\n\033#4{msg}\033[0m")73 elif color == 'magenta':74 print(f"\033[0;35m\033#3{msg}\n\033#4{msg}\033[0m")75 elif color == 'cyan':76 print(f"\033[0;36m\033#3{msg}\n\033#4{msg}\033[0m")77 else:78 print(f"\033#3{msg}\n\033#4{msg}")79# +80# function: get_utc()81# -82def get_utc(_days: int = 0) -> str:83 return (datetime.utcnow() + timedelta(days=_days)).isoformat()84# +85# function: get_jd()86# -87def get_jd(_days: int = 0) -> str:88 return Time(get_utc(_days=_days)).jd89# +90# class: NgClient()91# -92# noinspection PyBroadException93class NgClient(object):94 # +95 # method: __init__()96 # -97 def __init__(self, host: str = BOK_NG_HOST, port: int = BOK_NG_PORT,98 timeout: float = BOK_NG_TIMEOUT, simulate: bool = False, verbose: bool = False) -> None:99 # get input(s)100 self.host = host101 self.port = port102 self.timeout = timeout103 self.simulate = simulate104 self.verbose = verbose105 # set variable(s)106 self.__answer = f""107 self.__command = f""108 self.__encoder_a = math.nan109 self.__encoder_b = math.nan110 self.__encoder_c = math.nan111 self.__error = f""112 self.__gfilters = {}113 self.__gfilters_names = []114 self.__gfilters_numbers = []115 self.__gfilters_slots = []116 self.__gfilter_name = f""117 self.__gfilter_number = -1118 self.__gfilter_rotating = False119 self.__gdelta = math.nan120 self.__gfocus = math.nan121 self.__ifilters = {}122 self.__ifilters_names = []123 self.__ifilters_numbers = []124 self.__ifilters_slots = []125 self.__ifilter_error = -1126 self.__ifilter_inbeam = False127 self.__ifilter_name = f""128 self.__ifilter_number = -1129 self.__ifilter_rotating = False130 self.__ifilter_stop_code = -1131 self.__ifilter_translating = False132 self.__ifocus_a = math.nan133 self.__ifocus_b = math.nan134 self.__ifocus_c = math.nan135 self.__ifocus_mean = math.nan136 self.__sock = None137 # +138 # property(s)139 # -140 @property141 def host(self):142 return self.__host143 @host.setter144 def host(self, host: str = BOK_NG_HOST) -> None:145 self.__host = host if host.strip() != '' else BOK_NG_HOST146 @property147 def port(self):148 return self.__port149 @port.setter150 def port(self, port: int = BOK_NG_PORT) -> None:151 self.__port = port if port > 0 else BOK_NG_PORT152 @property153 def timeout(self):154 return self.__timeout155 @timeout.setter156 def timeout(self, timeout: float = BOK_NG_PORT) -> None:157 self.__timeout = timeout if timeout > 0.0 else BOK_NG_TIMEOUT158 @property159 def simulate(self):160 return self.__simulate161 @simulate.setter162 def simulate(self, simulate: bool = False) -> None:163 self.__simulate = simulate164 @property165 def verbose(self):166 return self.__verbose167 @verbose.setter168 def verbose(self, verbose: bool = False) -> None:169 self.__verbose = verbose170 # +171 # getter(s)172 # -173 @property174 def answer(self):175 return self.__answer176 @property177 def command(self):178 return self.__command179 @property180 def encoder_a(self):181 return self.__encoder_a182 @property183 def encoder_b(self):184 return self.__encoder_b185 @property186 def encoder_c(self):187 return self.__encoder_c188 @property189 def error(self):190 return self.__error191 @property192 def gfilters(self):193 return self.__gfilters194 @property195 def gfilters_names(self):196 return self.__gfilters_names197 @property198 def gfilters_numbers(self):199 return self.__gfilters_numbers200 @property201 def gfilters_slots(self):202 return self.__gfilters_slots203 @property204 def gfilter_name(self):205 return self.__gfilter_name206 @property207 def gfilter_number(self):208 return self.__gfilter_number209 @property210 def gfilter_rotating(self):211 return self.__gfilter_rotating212 @property213 def gdelta(self):214 return self.__gdelta215 @property216 def gfocus(self):217 return self.__gfocus218 @property219 def ifilters(self):220 return self.__ifilters221 @property222 def ifilters_names(self):223 return self.__ifilters_names224 @property225 def ifilters_numbers(self):226 return self.__ifilters_numbers227 @property228 def ifilters_slots(self):229 return self.__ifilters_slots230 @property231 def ifilter_error(self):232 return self.__ifilter_error233 @property234 def ifilter_inbeam(self):235 return self.__ifilter_inbeam236 @property237 def ifilter_name(self):238 return self.__ifilter_name239 @property240 def ifilter_number(self):241 return self.__ifilter_number242 @property243 def ifilter_rotating(self):244 return self.__ifilter_rotating245 @property246 def ifilter_stop_code(self):247 return self.__ifilter_stop_code248 @property249 def ifilter_translating(self):250 return self.__ifilter_translating251 @property252 def ifocus_a(self):253 return self.__ifocus_a254 @property255 def ifocus_b(self):256 return self.__ifocus_b257 @property258 def ifocus_c(self):259 return self.__ifocus_c260 @property261 def ifocus_mean(self):262 return self.__ifocus_mean263 @property264 def sock(self):265 return self.__sock266 # +267 # (hidden) method: __dump__()268 # -269 def __dump__(self):270 """ dump(s) variable(s) """271 pdh(f"self = {self}")272 pdh(f"self.__host = {self.__host}")273 pdh(f"self.__port = {self.__port}")274 pdh(f"self.__timeout = {self.__timeout}")275 pdh(f"self.__simulate = {self.__simulate}")276 pdh(f"self.__verbose = {self.__verbose}")277 pdh(f"self.__answer = '{self.__answer}'")278 pdh(f"self.__command = '{self.__command}'")279 pdh(f"self.__encoder_a = {self.__encoder_a}")280 pdh(f"self.__encoder_b = {self.__encoder_b}")281 pdh(f"self.__encoder_c = {self.__encoder_c}")282 pdh(f"self.__error = '{self.__error}'")283 pdh(f"self.__gfilters = {self.__gfilters}")284 pdh(f"self.__gfilters_names = {self.__gfilters_names}")285 pdh(f"self.__gfilters_numbers = {self.__gfilters_numbers}")286 pdh(f"self.__gfilters_slots = {self.__gfilters_slots}")287 pdh(f"self.__gfilter_name = '{self.__gfilter_name}'")288 pdh(f"self.__gfilter_number = {self.__gfilter_number}")289 pdh(f"self.__gfilter_rotating = {self.__gfilter_rotating}")290 pdh(f"self.__gdelta = {self.__gdelta}")291 pdh(f"self.__gfocus = {self.__gfocus}")292 pdh(f"self.__ifilters = {self.__ifilters}")293 pdh(f"self.__ifilters_names = {self.__ifilters_names}")294 pdh(f"self.__ifilters_numbers = {self.__ifilters_numbers}")295 pdh(f"self.__ifilters_slots = {self.__ifilters_slots}")296 pdh(f"self.__ifilter_error = {self.__ifilter_error}")297 pdh(f"self.__ifilter_inbeam = {self.__ifilter_inbeam}")298 pdh(f"self.__ifilter_name = '{self.__ifilter_name}'")299 pdh(f"self.__ifilter_number = {self.__ifilter_number}")300 pdh(f"self.__ifilter_rotating = {self.__ifilter_rotating}")301 pdh(f"self.__ifilter_stop_code = {self.__ifilter_stop_code}")302 pdh(f"self.__ifilter_translating = {self.__ifilter_translating}")303 pdh(f"self.__ifocus_a = {self.__ifocus_a}")304 pdh(f"self.__ifocus_b = {self.__ifocus_b}")305 pdh(f"self.__ifocus_c = {self.__ifocus_c}")306 pdh(f"self.__ifocus_mean = {self.__ifocus_mean}")307 pdh(f"self.__sock = None {self.__sock}")308 # +309 # method: connect()310 # -311 def connect(self) -> None:312 """ connects to host:port via socket """313 try:314 self.__sock = None315 self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)316 self.__sock.connect((socket.gethostbyname(self.__host), self.__port))317 self.__sock.settimeout(self.__timeout)318 except Exception as _:319 self.__error = f"{_}"320 self.__sock = None321 else:322 self.__error = f""323 # +324 # method: disconnect()325 # -326 def disconnect(self) -> None:327 """ disconnects socket """328 if self.__sock is not None and hasattr(self.__sock, 'close'):329 try:330 self.__sock.close()331 except Exception as _:332 self.__error = f"{_}"333 else:334 self.__error = f""335 self.__sock = None336 # +337 # method: converse()338 # -339 def converse(self, talk: str = f"") -> str:340 """ converses across socket """341 # send and recv data342 if talk.strip() == "":343 return f""344 # initialize variable(s)345 self.__answer = f""346 self.__error = f""347 # change command if simulate is enabled348 if self.__simulate:349 _cmd = talk.split()350 _cmd[2] = f"SIMULATE"351 self.__command = f"{' '.join(_cmd)}\r\n"352 else:353 self.__command = f"{talk}\r\n"354 # converse355 if self.__verbose:356 pdh(msg=f"\tSend> '{self.__command[:-2]}'", color='magenta', height=1)357 try:358 self.__sock.send(self.__command.encode())359 self.__answer = self.__sock.recv(BOK_NG_STRING).decode()360 except Exception as _:361 self.__answer = f""362 self.__error = f"{_}"363 else:364 self.__error = f""365 # return366 if self.__verbose:367 pdh(msg=f"\tRecv> '{self.__answer[:-1]}'", color='magenta', height=1)368 return self.__answer369 # +370 # method: parse_command_response()371 # -372 def parse_command_response(self, reply: str = '') -> bool:373 """ parses command response from socket """374 _reply = reply.upper()375 if not _reply.startswith(BOK_NG_TELESCOPE):376 return False377 elif BOK_NG_INSTRUMENT not in _reply:378 return False379 else:380 if " OK" in _reply:381 return True382 elif " ERROR" in _reply:383 self.__error = f"{_reply}".replace('\n', '')384 return False385 else:386 self.__error = f"{_reply} ERROR (unknown response)".replace('\n', '')387 return False388 # +389 # method: command_exit()390 # -391 def command_exit(self) -> bool:392 """ BOK 90PRIME <cmd-id> COMMAND EXIT """393 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND EXIT")394 return self.parse_command_response(_reply)395 # +396 # method: command_gfilter_init()397 # -398 def command_gfilter_init(self) -> bool:399 """ BOK 90PRIME <cmd-id> COMMAND GFILTER INIT """400 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND GFILTER INIT")401 return self.parse_command_response(_reply)402 # +403 # method: command_gfilter_name()404 # -405 def command_gfilter_name(self, gname: str = '') -> bool:406 """ BOK 90PRIME <cmd-id> COMMAND GFILTER NAME <str> """407 if gname.strip() == "":408 return False409 if not self.__gfilters:410 self.request_gfilters()411 if gname.strip() not in self.__gfilters_names:412 return False413 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND GFILTER NAME {gname}")414 return self.parse_command_response(_reply)415 # +416 # method: command_gfilter_number()417 # -418 def command_gfilter_number(self, gnumber: int = -1) -> bool:419 """ BOK 90PRIME <cmd-id> COMMAND GFILTER NUMBER <int> """420 if not self.__gfilters:421 self.request_gfilters()422 if gnumber not in self.__gfilters_numbers:423 return False424 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND GFILTER NUMBER {gnumber}")425 return self.parse_command_response(_reply)426 # +427 # method: command_gfocus_delta()428 # -429 def command_gfocus_delta(self, gdelta: float = math.nan) -> bool:430 """ BOK 90PRIME <cmd-id> COMMAND GFOCUS DELTA <float> """431 if math.nan < gdelta < -math.nan:432 return False433 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND GFOCUS DELTA {gdelta:.4f}")434 return self.parse_command_response(_reply)435 # +436 # method: command_ifilter_init()437 # -438 def command_ifilter_init(self) -> bool:439 """ BOK 90PRIME <cmd-id> COMMAND IFILTER INIT """440 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND IFILTER INIT")441 return self.parse_command_response(_reply)442 # +443 # method: command_ifilter_load()444 # -445 def command_ifilter_load(self) -> bool:446 """ BOK 90PRIME <cmd-id> COMMAND IFILTER LOAD """447 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND IFILTER LOAD")448 return self.parse_command_response(_reply)449 # +450 # method: command_ifilter_name()451 # -452 def command_ifilter_name(self, iname: str = '') -> bool:453 """ BOK 90PRIME <cmd-id> COMMAND IFILTER NAME <str> """454 if iname.strip() == "":455 return False456 if not self.__ifilters:457 self.request_ifilters()458 if iname.strip() not in self.__ifilters_names:459 return False460 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND IFILTER NAME {iname}")461 return self.parse_command_response(_reply)462 # +463 # method: command_ifilter_number()464 # -465 def command_ifilter_number(self, inumber: int = -1) -> bool:466 """ BOK 90PRIME <cmd-id> COMMAND IFILTER NUMBER <int> """467 if not self.__ifilters:468 self.request_ifilters()469 if inumber not in self.__ifilters_numbers:470 return False471 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND IFILTER NUMBER {inumber}")472 return self.parse_command_response(_reply)473 # +474 # method: command_ifilter_unload()475 # -476 def command_ifilter_unload(self) -> bool:477 """ BOK 90PRIME <cmd-id> COMMAND IFILTER UNLOAD """478 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND IFILTER UNLOAD")479 return self.parse_command_response(_reply)480 # +481 # method: command_ifocus()482 # -483 def command_ifocus(self, a: float = math.nan, b: float = math.nan, c: float = math.nan, t: float = math.nan) -> bool:484 """ BOK 90PRIME <cmd-id> COMMAND IFOCUS A <float> B <float> C <float> T <float> """485 if (math.nan < a < -math.nan) or (math.nan < b < -math.nan) or (math.nan < c < -math.nan) or (math.nan < t < -math.nan):486 return False487 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND IFOCUS A {a:.4f} B {b:.4f} C {c:.4f} T {t:.4f}")488 return self.parse_command_response(_reply)489 # +490 # method: command_ifocus_delta()491 # -492 def command_ifocus_delta(self, idelta: float = math.nan, t: float = math.nan) -> bool:493 """ BOK 90PRIME <cmd-id> COMMAND IFOCUS DELTA <float> T <float> """494 if (math.nan < idelta < -math.nan) or (math.nan < t < -math.nan):495 return False496 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND IFOCUS DELTA {idelta:.4f} T {t:.4f}")497 return self.parse_command_response(_reply)498 # +499 # method: command_lvdt()500 # -501 def command_lvdt(self, a: float = math.nan, b: float = math.nan, c: float = math.nan, t: float = math.nan) -> bool:502 """ BOK 90PRIME <cmd-id> COMMAND LVDT A <float> B <float> C <float> T <float> """503 if (math.nan < a < -math.nan) or (math.nan < b < -math.nan) or (math.nan < c < -math.nan) or (math.nan < t < -math.nan):504 return False505 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND LVDT A {a:.4f} B {b:.4f} C {c:.4f} T {t:.4f}")506 return self.parse_command_response(_reply)507 # +508 # method: command_lvdtall()509 # -510 def command_lvdtall(self, lvdt: float = math.nan, t: float = math.nan) -> bool:511 """ BOK 90PRIME <cmd-id> COMMAND LVDTALL <float> T <float> """512 if (math.nan < lvdt < -math.nan) or (math.nan < t < -math.nan):513 return False514 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND LVDTALL {lvdt:.4f} T {t:.4f}")515 return self.parse_command_response(_reply)516 # +517 # method: command_test()518 # -519 def command_test(self) -> bool:520 """ BOK 90PRIME <cmd-id> COMMAND TEST """521 _reply = self.converse(f"BOK 90PRIME {get_jd()} COMMAND TEST")522 return self.parse_command_response(_reply)523 # +524 # method: request_encoders()525 # -526 def request_encoders(self) -> None:527 """ BOK 90PRIME <cmd-id> REQUEST ENCODERS """528 # talk to hardware529 self.converse(f"BOK 90PRIME {get_jd()} REQUEST ENCODERS")530 # parse answer, eg 'BOK 90PRIME <cmd-id> ERROR (reason)'531 if 'ERROR' in self.__answer:532 self.__error = f"{self.__answer}"533 # parse answer, eg 'BOK 90PRIME <cmd-id> OK A=-0.355 B=1.443 C=0.345'534 elif 'OK' in self.__answer:535 for _elem in self.__answer.split():536 if 'A=' in _elem:537 try:538 self.__encoder_a = float(_elem.split('=')[1])539 except Exception as _ea:540 self.__error = f"{_ea}"541 self.__encoder_a = math.nan542 else:543 self.__error = f""544 elif 'B=' in _elem:545 try:546 self.__encoder_b = float(_elem.split('=')[1])547 except Exception as _eb:548 self.__error = f"{_eb}"549 self.__encoder_b = math.nan550 else:551 self.__error = f""552 elif 'C=' in _elem:553 try:554 self.__encoder_c = float(_elem.split('=')[1])555 except Exception as _ec:556 self.__error = f"{_ec}"557 self.__encoder_c = math.nan558 else:559 self.__error = f""560 # +561 # method: request_gfilter()562 # -563 def request_gfilter(self) -> None:564 """ BOK 90PRIME <cmd-id> REQUEST GFILTER """565 # talk to hardware566 self.converse(f"BOK 90PRIME {get_jd()} REQUEST GFILTER")567 # parse answer, eg 'BOK 90PRIME <cmd-id> ERROR (reason)'568 if 'ERROR' in self.__answer:569 self.__error = f"{self.__error}, {self.__answer}"570 # parse answer, eg 'BOK 90PRIME <cmd-id> OK SNUM=4:red ROTATING=False'571 elif 'OK' in self.__answer:572 for _elem in self.__answer.split():573 if 'SNUM=' in _elem:574 try:575 self.__gfilter_name = f"{_elem.split('=')[1].split(':')[1]}"576 self.__gfilter_number = int(_elem.split('=')[1].split(':')[0])577 except Exception as _eg:578 self.__error = f"{_eg}"579 self.__gfilter_name = f""580 self.__gfilter_number = -1581 else:582 self.__error = f""583 elif 'ROTATING=' in _elem:584 try:585 self.__gfilter_rotating = True if _elem.split('=')[1].lower() in BOK_NG_TRUE else False586 except Exception as _er:587 self.__error = f"{_er}"588 self.__gfilter_rotating = f"Unknown"589 else:590 self.__error = f""591 # +592 # method: request_gfilters()593 # -594 def request_gfilters(self) -> None:595 """ BOK 90PRIME <cmd-id> REQUEST GFILTERS """596 # talk to hardware597 self.converse(f"BOK 90PRIME {get_jd()} REQUEST GFILTERS")598 # parse answer, eg 'BOK 90PRIME <cmd-id> ERROR (reason)'599 if 'ERROR' in self.__answer:600 self.__error = f"{self.__error}, {self.__answer}"601 # parse answer, eg 'BOK 90PRIME <cmd-id> OK 1=1:green 2=2:open 3=3:neutral 4=4:red 5=5:open 6=6:blue'602 elif 'OK' in self.__answer:603 self.__error, self.__gfilters = f"", {}604 for _elem in self.__answer.split():605 if '=' in _elem:606 try:607 _slot = int(_elem.split('=')[0])608 except Exception as _es:609 self.__error = f"{_es}"610 _slot = -1611 else:612 self.__error = f""613 if _slot in BOK_NG_GFILTER_SLOTS:614 try:615 _name = _elem.split('=')[1].split(':')[1]616 _number = int(_elem.split('=')[1].split(':')[0])617 except Exception as _en:618 self.__error = f"{_en}"619 _name = f""620 _number = -1621 else:622 self.__error = f""623 self.__gfilters = {**self.__gfilters,624 **{f"Slot {_slot}": {"Number": _number, "Name": _name}}}625 # parse dictionary626 self.__gfilters_names = [_v['Name'] for _k, _v in self.__gfilters.items()]627 self.__gfilters_numbers = [_v['Number'] for _k, _v in self.__gfilters.items()]628 self.__gfilters_slots = [int(_.split()[1]) for _ in self.__gfilters]629 # +630 # method: request_gfocus()631 # -632 def request_gfocus(self) -> None:633 """ BOK 90PRIME <cmd-id> REQUEST GFOCUS """634 # talk to hardware635 self.converse(f"BOK 90PRIME {get_jd()} REQUEST GFOCUS")636 # parse answer, eg 'BOK 90PRIME <cmd-id> ERROR (reason)'637 if 'ERROR' in self.__answer:638 self.__error = f"{self.__error}, {self.__answer}"639 # parse answer, eg 'BOK 90PRIME <cmd-id> OK GFOCUS=-0.355'640 elif 'OK' in self.__answer:641 for _elem in self.__answer.split():642 if 'GFOCUS=' in _elem:643 try:644 self.__gfocus = float(_elem.split('=')[1])645 except Exception as _eg:646 self.__error = f"{_eg}"647 self.__gfocus = math.nan648 else:649 self.__error = f""650 # +651 # method: request_ifilter()652 # -653 def request_ifilter(self) -> None:654 """ BOK 90PRIME <cmd-id> REQUEST IFILTER """655 # talk to hardware656 self.converse(f"BOK 90PRIME {get_jd()} REQUEST IFILTER")657 # parse answer, eg 'BOK 90PRIME <cmd-id> ERROR (reason)'658 if 'ERROR' in self.__answer:659 self.__error = f"{self.__error}, {self.__answer}"660 # parse answer, eg 'BOK 90PRIME <cmd-id> OK FILTVAL=18:Bob INBEAM=True ROTATING=False TRANSLATING=False ERRFILT=<int> FILTTSC=<int>'661 elif 'OK' in self.__answer:662 self.__error = f""663 for _elem in self.__answer.split():664 if 'FILTVAL=' in _elem:665 try:666 self.__ifilter_name = f"{_elem.split('=')[1].split(':')[1]}"667 self.__ifilter_number = int(_elem.split('=')[1].split(':')[0])668 except Exception as _ef:669 self.__error = f"{_ef}"670 self.__ifilter_name = f""671 self.__ifilter_number = -1672 else:673 self.__error = f""674 elif 'INBEAM=' in _elem:675 try:676 self.__ifilter_inbeam = True if _elem.split('=')[1].lower() in BOK_NG_TRUE else False677 except Exception as _ei:678 self.__error = f"{_ei}"679 self.__ifilter_inbeam = f"Unknown"680 else:681 self.__error = f""682 elif 'ROTATING=' in _elem:683 try:684 self.__ifilter_rotating = True if _elem.split('=')[1].lower() in BOK_NG_TRUE else False685 except Exception as _er:686 self.__error = f"{_er}"687 self.__ifilter_rotating = f"Unknown"688 else:689 self.__error = f""690 elif 'TRANSLATING=' in _elem:691 try:692 self.__ifilter_translating = True if _elem.split('=')[1].lower() in BOK_NG_TRUE else False693 except Exception as _et:694 self.__error = f"{_et}"695 self.__ifilter_translating = f"Unknown"696 else:697 self.__error = f""698 elif 'ERRFILT=' in _elem:699 try:700 self.__ifilter_error = int(_elem.split('=')[1])701 except Exception as _ef:702 self.__error = f"{_ef}"703 self.__ifilter_number = -1704 else:705 self.__error = f""706 elif 'FILTTSC=' in _elem:707 try:708 self.__ifilter_stop_code = int(_elem.split('=')[1])709 except Exception as _ef:710 self.__error = f"{_ef}"711 self.__ifilter_stop_code = -1712 else:713 self.__error = f""714 # +715 # method: request_ifilters()716 # -717 def request_ifilters(self) -> None:718 """ BOK 90PRIME <cmd-id> REQUEST IFILTERS """719 # talk to hardware720 self.converse(f"BOK 90PRIME {get_jd()} REQUEST IFILTERS")721 # parse answer, eg 'BOK 90PRIME <cmd-id> ERROR (reason)'722 if 'ERROR' in self.__answer:723 self.__error = f"{self.__error}, {self.__answer}"724 # parse answer , eg 'BOK 90PRIME <cmd-id> OK 0=18:Bob 1=2:g 2=3:r 3=4:i 4=5:z 5=6:u'725 elif 'OK' in self.__answer:726 self.__error, self.__ifilters = f"", {}727 for _elem in self.__answer.split():728 if '=' in _elem:729 try:730 _slot = int(_elem.split('=')[0])731 except Exception as _es:732 self.__error = f"{_es}"733 _slot = -1734 else:735 self.__error = f""736 if _slot in BOK_NG_IFILTER_SLOTS:737 try:738 _name = _elem.split('=')[1].split(':')[1]739 _number = int(_elem.split('=')[1].split(':')[0])740 except Exception as _en:741 self.__error = f"{_en}"742 _name = f""743 _number = -1744 else:745 self.__error = f""746 self.__ifilters = {**self.__ifilters,747 **{f"Slot {_slot}": {"Number": _number, "Name": _name}}}748 # parse dictionary749 self.__ifilters_names = [_v['Name'] for _k, _v in self.__ifilters.items()]750 self.__ifilters_numbers = [_v['Number'] for _k, _v in self.__ifilters.items()]751 self.__ifilters_slots = [int(_.split()[1]) for _ in self.__ifilters]752 # +753 # method: request_ifocus()754 # -755 def request_ifocus(self) -> None:756 """ BOK 90PRIME <cmd-id> REQUEST IFOCUS """757 # talk to hardware758 self.converse(f"BOK 90PRIME {get_jd()} REQUEST IFOCUS")759 # parse answer, eg 'BOK 90PRIME <cmd-id> ERROR (reason)'760 if 'ERROR' in self.__answer:761 self.__error = f"{self.__answer}"762 # parse answer, eg 'BOK 90PRIME <cmd-id> OK A=355 B=443 C=345'763 elif 'OK' in self.__answer:764 for _elem in self.__answer.split():765 if 'A=' in _elem:766 try:767 self.__ifocus_a = float(_elem.split('=')[1])768 except Exception as _ea:769 self.__error = f"{_ea}"770 self.__ifocus_a = math.nan771 else:772 self.__error = f""773 elif 'B=' in _elem:774 try:775 self.__ifocus_b = float(_elem.split('=')[1])776 except Exception as _eb:777 self.__error = f"{_eb}"778 self.__ifocus_b = math.nan779 else:780 self.__error = f""781 elif 'C=' in _elem:782 try:783 self.__ifocus_c = float(_elem.split('=')[1])784 except Exception as _ec:785 self.__error = f"{_ec}"786 self.__ifocus_c = math.nan787 else:788 self.__error = f""789 elif 'MEAN=' in _elem:790 try:791 self.__ifocus_mean = float(_elem.split('=')[1])792 except Exception as _em:793 self.__error = f"{_em}"794 self.__ifocus_mean = math.nan795 else:796 self.__error = f""797# +798# function: ngclient_check()799# -800def ngclient_check(_host: str = BOK_NG_HOST, _port: int = BOK_NG_PORT, _timeout: float = BOK_NG_TIMEOUT, 801 _simulate: bool = False, _verbose: bool = False) -> None:802 # exercise command(s) and request(s)803 _client = None804 try:805 # instantiate client and connect to server806 pdh(msg=f"Executing> NgClient(host='{_host}', port={_port}, timeout={_timeout}, simulate={_simulate}, verbose={_verbose})", color='green', height=1)807 _client = NgClient(host=_host, port=_port, timeout=_timeout, simulate=_simulate, verbose=_verbose)808 _client.connect()809 if _client.sock is not None:810 pdh(msg=f"\tInstantiation OK, sock={_client.sock}", color='green', height=1)811 else:812 pdh(msg=f"\tInstantiation FAILED, error={_client.error}", color='red', height=1)813 return814 # +815 # request(s)816 # -817 # request_encoders()818 pdh(msg=f"Executing> request_encoders()", color='green', height=1)819 _client.request_encoders()820 if _client.error == '':821 pdh(msg=f"\tencoder_a = {_client.encoder_a}", color='green', height=1)822 pdh(msg=f"\tencoder_b = {_client.encoder_b}", color='green', height=1)823 pdh(msg=f"\tencoder_c = {_client.encoder_c}", color='green', height=1)824 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):825 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')826 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)827 # request_gfilters()828 pdh(msg=f"Executing> request_gfilters()", color='green', height=1)829 _client.request_gfilters()830 if _client.error == '':831 pdh(msg=f"\tgfilters = {_client.gfilters}", color='green', height=1)832 pdh(msg=f"\tgfilters_names = {_client.gfilters_names}", color='green', height=1)833 pdh(msg=f"\tgfilters_numbers = {_client.gfilters_numbers}", color='green', height=1)834 pdh(msg=f"\tgfilters_slots = {_client.gfilters_slots}", color='green', height=1)835 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):836 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')837 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)838 # request_gfilter()839 pdh(msg=f"Executing> request_gfilter()", color='green', height=1)840 _client.request_gfilter()841 if _client.error == '':842 pdh(msg=f"\tgfilter_name = '{_client.gfilter_name}'", color='green', height=1)843 pdh(msg=f"\tgfilter_number = {_client.gfilter_number}", color='green', height=1)844 pdh(msg=f"\tgfilter_rotating = {_client.gfilter_rotating}", color='green', height=1)845 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):846 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')847 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)848 # request_gfocus()849 pdh(msg=f"Executing> request_gfocus()", color='green', height=1)850 _client.request_gfocus()851 if _client.error == '':852 pdh(msg=f"\tgfocus = {_client.gfocus}", color='green', height=1)853 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):854 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')855 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)856 # request_ifilters()857 pdh(msg=f"Executing> request_ifilters()", color='green', height=1)858 _client.request_ifilters()859 if _client.error == '':860 pdh(msg=f"\tifilters = {_client.ifilters}", color='green', height=1)861 pdh(msg=f"\tifilters_names = {_client.ifilters_names}", color='green', height=1)862 pdh(msg=f"\tifilters_numbers = {_client.ifilters_numbers}", color='green', height=1)863 pdh(msg=f"\tifilters_slots = {_client.ifilters_slots}", color='green', height=1)864 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):865 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')866 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)867 # request_ifilter()868 pdh(msg=f"Executing> request_ifilter()", color='green', height=1)869 _client.request_ifilter()870 if _client.error == '':871 pdh(msg=f"\tifilter_error = {_client.ifilter_error}", color='green', height=1)872 pdh(msg=f"\tifilter_inbeam = {_client.ifilter_inbeam}", color='green', height=1)873 pdh(msg=f"\tifilter_name = {_client.ifilter_name}", color='green', height=1)874 pdh(msg=f"\tifilter_number = {_client.ifilter_number}", color='green', height=1)875 pdh(msg=f"\tifilter_rotating = {_client.ifilter_rotating}", color='green', height=1)876 pdh(msg=f"\tifilter_stop_code = {_client.ifilter_stop_code}", color='green', height=1)877 pdh(msg=f"\tifilter_translating = {_client.ifilter_translating}", color='green', height=1)878 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):879 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')880 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)881 # request_ifocus()882 pdh(msg=f"Executing> request_ifocus()", color='green', height=1)883 _client.request_ifocus()884 if _client.error == '':885 pdh(msg=f"\tifocus_a = {_client.ifocus_a}", color='green', height=1)886 pdh(msg=f"\tifocus_b = {_client.ifocus_b}", color='green', height=1)887 pdh(msg=f"\tifocus_c = {_client.ifocus_c}", color='green', height=1)888 pdh(msg=f"\tifocus_mean = {_client.ifocus_mean}", color='green', height=1)889 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):890 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')891 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)892 if _verbose:893 _client.__dump__()894 # +895 # command(s)896 # -897 # command_gfilter_init()898 pdh(msg=f"Executing> command_gfilter_init() ...", color='green', height=1)899 if _client.command_gfilter_init():900 pdh(msg=f"\tcommand_gfilter_init() succeeded", color='green', height=1)901 else:902 pdh(msg=f"\tcommand_gfilter_init() failed", color='red', height=1)903 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):904 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')905 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)906 _client.request_gfilters()907 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):908 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')909 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)910 _client.request_gfilter()911 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):912 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')913 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)914 # command_gfilter_name()915 _gfilter_name = random.choice(_client.gfilters_names)916 if _gfilter_name not in _client.gfilter_name:917 pdh(msg=f"Executing> command_gfilter_name('{_gfilter_name}') ...", color='green', height=1)918 if _client.command_gfilter_name(gname=_gfilter_name):919 pdh(msg=f"\tcommand_gfilter_name('{_gfilter_name}') succeeded", color='green', height=1)920 else:921 pdh(msg=f"\tcommand_gfilter_name('{_gfilter_name}') failed", color='red', height=1)922 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):923 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')924 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)925 # command_gfilter_number()926 _gfilter_number = random.choice(_client.gfilters_numbers)927 if _gfilter_number != _client.gfilter_number:928 pdh(msg=f"Executing> command_gfilter_number({_gfilter_number}) ...", color='green', height=1)929 if _client.command_gfilter_number(gnumber=_gfilter_number):930 pdh(msg=f"\tcommand_gfilter_number({_gfilter_number}) succeeded", color='green', height=1)931 else:932 pdh(msg=f"\tcommand_gfilter_number({_gfilter_number}) failed", color='red', height=1)933 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):934 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')935 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)936 # command_gfilter_name('open')937 if 'open' not in _client.gfilter_name:938 pdh(msg=f"Executing> command_gfilter_name('open') ...", color='green', height=1)939 if _client.command_gfilter_name(gname='open'):940 pdh(msg=f"\tcommand_gfilter_name('open') succeeded", color='green', height=1)941 else:942 pdh(msg=f"\tcommand_gfilter_name('open') failed", color='red', height=1)943 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):944 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')945 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)946 # command_gfocus_delta()947 _gfocus_delta = random.uniform(-100.0, 100.0)948 pdh(msg=f"Executing> command_gfocus_delta({_gfocus_delta:.4f}) ...", color='green', height=1)949 if _client.command_gfocus_delta(gdelta=_gfocus_delta):950 pdh(msg=f"\tcommand_gfocus_delta({_gfocus_delta:.4f}) succeeded", color='green', height=1)951 else:952 pdh(msg=f"\tcommand_gfocus_delta({_gfocus_delta:.4f}) failed", color='red', height=1)953 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):954 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')955 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)956 _gfocus_delta *= -1.0957 pdh(msg=f"Executing> command_gfocus_delta({_gfocus_delta:.4f}) ...", color='green', height=1)958 if _client.command_gfocus_delta(gdelta=_gfocus_delta):959 pdh(msg=f"\tcommand_gfocus_delta({_gfocus_delta:.4f}) succeeded", color='green', height=1)960 else:961 pdh(msg=f"\tcommand_gfocus_delta({_gfocus_delta:.4f}) failed", color='red', height=1)962 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):963 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')964 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)965 # command_ifilter_unload()966 # command_ifilter_init()967 pdh(msg=f"Executing> command_ifilter_unload() ...", color='green', height=1)968 if _client.command_ifilter_unload():969 pdh(msg=f"\tcommand_ifilter_unload() succeeded", color='green', height=1)970 else:971 pdh(msg=f"\tcommand_ifilter_unload() failed", color='red', height=1)972 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):973 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')974 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)975 pdh(msg=f"Executing> command_ifilter_init() ...", color='green', height=1)976 if _client.command_ifilter_init():977 pdh(msg=f"\tcommand_ifilter_init() succeeded", color='green', height=1)978 else:979 pdh(msg=f"\tcommand_ifilter_init() failed", color='red', height=1)980 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):981 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')982 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)983 _client.request_ifilters()984 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):985 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')986 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)987 _client.request_ifilter()988 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):989 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')990 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)991 # command_ifilter_unload()992 # command_ifilter_name()993 # command_ifilter_load()994 pdh(msg=f"Executing> command_ifilter_unload() ...", color='green', height=1)995 if _client.command_ifilter_unload():996 pdh(msg=f"\tcommand_ifilter_unload() succeeded", color='green', height=1)997 else:998 pdh(msg=f"\tcommand_ifilter_unload() failed", color='red', height=1)999 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):1000 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')1001 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)1002 _ifilter_name = random.choice(_client.ifilters_names)1003 if _ifilter_name not in _client.ifilter_name:1004 pdh(msg=f"Executing> command_ifilter_name('{_ifilter_name}') ...", color='green', height=1)1005 if _client.command_ifilter_name(iname=_ifilter_name):1006 pdh(msg=f"\tcommand_ifilter_name('{_ifilter_name}') succeeded", color='green', height=1)1007 else:1008 pdh(msg=f"\tcommand_ifilter_name('{_ifilter_name}') failed", color='red', height=1)1009 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):1010 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')1011 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)1012 pdh(msg=f"Executing> command_ifilter_load() ...", color='green', height=1)1013 if _client.command_ifilter_load():1014 pdh(msg=f"\tcommand_ifilter_load() succeeded", color='green', height=1)1015 else:1016 pdh(msg=f"\tcommand_ifilter_load() failed", color='red', height=1)1017 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):1018 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')1019 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)1020 # command_ifilter_unload()1021 # command_ifilter_number()1022 # command_ifilter_load()1023 pdh(msg=f"Executing> command_ifilter_unload() ...", color='green', height=1)1024 if _client.command_ifilter_unload():1025 pdh(msg=f"\tcommand_ifilter_unload() succeeded", color='green', height=1)1026 else:1027 pdh(msg=f"\tcommand_ifilter_unload() failed", color='red', height=1)1028 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):1029 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')1030 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)1031 _ifilter_number = random.choice(_client.ifilters_numbers)1032 if _ifilter_number != _client.ifilter_number:1033 pdh(msg=f"Executing> command_ifilter_number({_ifilter_number}) ...", color='green', height=1)1034 if _client.command_ifilter_number(inumber=_ifilter_number):1035 pdh(msg=f"\tcommand_ifilter_number({_ifilter_number}) succeeded", color='green', height=1)1036 else:1037 pdh(msg=f"\tcommand_ifilter_number({_ifilter_number}) failed", color='red', height=1)1038 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):1039 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')1040 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)1041 pdh(msg=f"Executing> command_ifilter_load() ...", color='green', height=1)1042 if _client.command_ifilter_load():1043 pdh(msg=f"\tcommand_ifilter_load() succeeded", color='green', height=1)1044 else:1045 pdh(msg=f"\tcommand_ifilter_load() failed", color='red', height=1)1046 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):1047 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')1048 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)1049 # command_ifocus()1050 _ifocus_a = random.uniform(250.0, 350.0)1051 _ifocus_b = random.uniform(250.0, 350.0)1052 _ifocus_c = random.uniform(250.0, 350.0)1053 _tolerance = random.uniform(10.0, 20.0)1054 pdh(msg=f"Executing> command_ifocus({_ifocus_a:.4f}, {_ifocus_b:.4f}, {_ifocus_c:.4f}, {_tolerance:.4f}) ...", color='green', height=1)1055 if _client.command_ifocus(a=_ifocus_a, b=_ifocus_b, c=_ifocus_c, t=_tolerance):1056 pdh(msg=f"\tcommand_ifocus({_ifocus_a:.4f}, {_ifocus_b:.4f}, {_ifocus_c:.4f}, {_tolerance:.4f}) succeeded", color='green', height=1)1057 else:1058 pdh(msg=f"\tcommand_ifocus({_ifocus_a:.4f}, {_ifocus_b:.4f}, {_ifocus_c:.4f}, {_tolerance:.4f}) failed", color='red', height=1)1059 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):1060 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')1061 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)1062 _ifocus_delta = random.uniform(-50.0, 50.0)1063 pdh(msg=f"Executing> command_ifocus_delta({_ifocus_delta:.4f}, {_tolerance:.4f}) ...", color='green', height=1)1064 if _client.command_ifocus_delta(idelta=_ifocus_delta, t=_tolerance):1065 pdh(msg=f"\tcommand_ifocus_delta({_ifocus_delta:.4f}, {_tolerance:.4f}) succeeded", color='green', height=1)1066 else:1067 pdh(msg=f"\tcommand_ifocus_delta({_ifocus_delta:.4f}, {_tolerance:.4f}) failed", color='red', height=1)1068 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):1069 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')1070 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)1071 _ifocus_delta *= -1.01072 pdh(msg=f"Executing> command_ifocus_delta({_ifocus_delta:.4f}, {_tolerance:.4f}) ...", color='green', height=1)1073 if _client.command_ifocus_delta(idelta=_ifocus_delta, t=_tolerance):1074 pdh(msg=f"\tcommand_ifocus_delta({_ifocus_delta:.4f}, {_tolerance:.4f}) succeeded", color='green', height=1)1075 else:1076 pdh(msg=f"\tcommand_ifocus_delta({_ifocus_delta:.4f}, {_tolerance:.4f}) failed", color='red', height=1)1077 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):1078 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')1079 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)1080 # command_test()1081 pdh(msg=f"Executing> command_test() ...", color='green', height=1)1082 if _client.command_test():1083 pdh(msg=f"\tcommand_test() succeeded", color='green', height=1)1084 else:1085 pdh(msg=f"\tcommand_test() failed", color='red', height=1)1086 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):1087 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')1088 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)1089 # command_exit()1090 pdh(msg=f"Executing> command_exit() ...", color='green', height=1)1091 if _client.command_exit():1092 pdh(msg=f"\tcommand_exit() succeeded", color='green', height=1)1093 if _client is not None and hasattr(_client, 'disconnect'):1094 _client.disconnect()1095 _client = None1096 else:1097 pdh(msg=f"\tcommand_exit() failed", color='red', height=1)1098 if _verbose and _client is not None and hasattr(_client, 'answer') and hasattr(_client, 'error'):1099 _ans, _err = _client.answer.replace('\n', ''), _client.error.replace('\n', '')1100 pdh(msg=f"\tverbose> answer='{_ans}', error='{_err}'", color='blue', height=1)1101 except Exception as _x:1102 print(f"{_x}")1103 if _client is not None and hasattr(_client, 'error'):1104 print(f"{_client.error}")1105 # disconnect from server1106 if _client is not None and hasattr(_client, 'disconnect'):1107 _client.disconnect()1108# +1109# main()1110# -1111if __name__ == '__main__':1112 # get command line argument(s)1113 _p = argparse.ArgumentParser(description='Galil_DMC_22x0_TCP_Read', formatter_class=argparse.RawTextHelpFormatter)1114 _p.add_argument('--commands', default=False, action='store_true', help='Show supported commands')1115 _p.add_argument('--host', default=f"{BOK_NG_HOST}", help="""Host [%(default)s]""")1116 _p.add_argument('--port', default=BOK_NG_PORT, help="""Port [%(default)s]""")1117 _p.add_argument('--timeout', default=BOK_NG_TIMEOUT, help="""Timeout (s) [%(default)s]""")1118 _p.add_argument('--simulate', default=False, action='store_true', help='Simulate')1119 _p.add_argument('--verbose', default=False, action='store_true', help='Verbose')1120 _args = _p.parse_args()1121 # noinspection PyBroadException1122 try:1123 if bool(_args.commands):1124 with open(BOK_NG_HELP, 'r') as _f:1125 print(f"{_f.read()}")1126 else:1127 ngclient_check(_host=_args.host, _port=int(_args.port), _timeout=float(_args.timeout), _simulate=bool(_args.simulate), _verbose=bool(_args.verbose))1128 except Exception as _:...

Full Screen

Full Screen

climate.py

Source:climate.py Github

copy

Full Screen

1"""Support for Venstar WiFi Thermostats."""2from __future__ import annotations3import voluptuous as vol4from homeassistant.components.climate import PLATFORM_SCHEMA, ClimateEntity5from homeassistant.components.climate.const import (6 ATTR_HVAC_MODE,7 ATTR_TARGET_TEMP_HIGH,8 ATTR_TARGET_TEMP_LOW,9 CURRENT_HVAC_COOL,10 CURRENT_HVAC_HEAT,11 CURRENT_HVAC_IDLE,12 CURRENT_HVAC_OFF,13 FAN_AUTO,14 FAN_ON,15 HVAC_MODE_AUTO,16 HVAC_MODE_COOL,17 HVAC_MODE_HEAT,18 HVAC_MODE_OFF,19 PRESET_AWAY,20 PRESET_NONE,21 SUPPORT_FAN_MODE,22 SUPPORT_PRESET_MODE,23 SUPPORT_TARGET_HUMIDITY,24 SUPPORT_TARGET_TEMPERATURE,25 SUPPORT_TARGET_TEMPERATURE_RANGE,26)27from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry28from homeassistant.const import (29 ATTR_TEMPERATURE,30 CONF_HOST,31 CONF_PASSWORD,32 CONF_PIN,33 CONF_SSL,34 CONF_TIMEOUT,35 CONF_USERNAME,36 PRECISION_HALVES,37 STATE_ON,38 TEMP_CELSIUS,39 TEMP_FAHRENHEIT,40)41from homeassistant.core import HomeAssistant42import homeassistant.helpers.config_validation as cv43from homeassistant.helpers.entity_platform import AddEntitiesCallback44from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType45from . import VenstarDataUpdateCoordinator, VenstarEntity46from .const import (47 _LOGGER,48 ATTR_FAN_STATE,49 ATTR_HVAC_STATE,50 CONF_HUMIDIFIER,51 DEFAULT_SSL,52 DOMAIN,53 HOLD_MODE_TEMPERATURE,54 VALID_FAN_STATES,55 VALID_THERMOSTAT_MODES,56)57PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(58 {59 vol.Required(CONF_HOST): cv.string,60 vol.Optional(CONF_PASSWORD): cv.string,61 vol.Optional(CONF_HUMIDIFIER, default=True): cv.boolean,62 vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean,63 vol.Optional(CONF_TIMEOUT, default=5): vol.All(64 vol.Coerce(int), vol.Range(min=1)65 ),66 vol.Optional(CONF_USERNAME): cv.string,67 vol.Optional(CONF_PIN): cv.string,68 }69)70async def async_setup_entry(71 hass: HomeAssistant,72 config_entry: ConfigEntry,73 async_add_entities: AddEntitiesCallback,74) -> None:75 """Set up the Venstar thermostat."""76 venstar_data_coordinator = hass.data[DOMAIN][config_entry.entry_id]77 async_add_entities(78 [79 VenstarThermostat(80 venstar_data_coordinator,81 config_entry,82 )83 ],84 )85async def async_setup_platform(86 hass: HomeAssistant,87 config: ConfigType,88 add_entities: AddEntitiesCallback,89 discovery_info: DiscoveryInfoType | None = None,90) -> None:91 """Set up the Venstar thermostat platform.92 Venstar uses config flow for configuration now. If an entry exists in93 configuration.yaml, the import flow will attempt to import it and create94 a config entry.95 """96 _LOGGER.warning(97 "Loading venstar via platform config is deprecated; The configuration"98 " has been migrated to a config entry and can be safely removed"99 )100 # No config entry exists and configuration.yaml config exists, trigger the import flow.101 if not hass.config_entries.async_entries(DOMAIN):102 await hass.config_entries.flow.async_init(103 DOMAIN, context={"source": SOURCE_IMPORT}, data=config104 )105class VenstarThermostat(VenstarEntity, ClimateEntity):106 """Representation of a Venstar thermostat."""107 def __init__(108 self,109 venstar_data_coordinator: VenstarDataUpdateCoordinator,110 config: ConfigEntry,111 ) -> None:112 """Initialize the thermostat."""113 super().__init__(venstar_data_coordinator, config)114 self._mode_map = {115 HVAC_MODE_HEAT: self._client.MODE_HEAT,116 HVAC_MODE_COOL: self._client.MODE_COOL,117 HVAC_MODE_AUTO: self._client.MODE_AUTO,118 }119 self._attr_unique_id = config.entry_id120 self._attr_name = self._client.name121 @property122 def supported_features(self):123 """Return the list of supported features."""124 features = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE | SUPPORT_PRESET_MODE125 if self._client.mode == self._client.MODE_AUTO:126 features |= SUPPORT_TARGET_TEMPERATURE_RANGE127 if self._client.hum_setpoint is not None:128 features |= SUPPORT_TARGET_HUMIDITY129 return features130 @property131 def precision(self):132 """Return the precision of the system.133 Venstar temperature values are passed back and forth in the134 API in C or F, with half-degree accuracy.135 """136 return PRECISION_HALVES137 @property138 def temperature_unit(self):139 """Return the unit of measurement, as defined by the API."""140 if self._client.tempunits == self._client.TEMPUNITS_F:141 return TEMP_FAHRENHEIT142 return TEMP_CELSIUS143 @property144 def fan_modes(self):145 """Return the list of available fan modes."""146 return VALID_FAN_STATES147 @property148 def hvac_modes(self):149 """Return the list of available operation modes."""150 return VALID_THERMOSTAT_MODES151 @property152 def current_temperature(self):153 """Return the current temperature."""154 return self._client.get_indoor_temp()155 @property156 def current_humidity(self):157 """Return the current humidity."""158 return self._client.get_indoor_humidity()159 @property160 def hvac_mode(self):161 """Return current operation mode ie. heat, cool, auto."""162 if self._client.mode == self._client.MODE_HEAT:163 return HVAC_MODE_HEAT164 if self._client.mode == self._client.MODE_COOL:165 return HVAC_MODE_COOL166 if self._client.mode == self._client.MODE_AUTO:167 return HVAC_MODE_AUTO168 return HVAC_MODE_OFF169 @property170 def hvac_action(self):171 """Return current operation mode ie. heat, cool, auto."""172 if self._client.state == self._client.STATE_IDLE:173 return CURRENT_HVAC_IDLE174 if self._client.state == self._client.STATE_HEATING:175 return CURRENT_HVAC_HEAT176 if self._client.state == self._client.STATE_COOLING:177 return CURRENT_HVAC_COOL178 return CURRENT_HVAC_OFF179 @property180 def fan_mode(self):181 """Return the current fan mode."""182 if self._client.fan == self._client.FAN_ON:183 return FAN_ON184 return FAN_AUTO185 @property186 def extra_state_attributes(self):187 """Return the optional state attributes."""188 return {189 ATTR_FAN_STATE: self._client.fanstate,190 ATTR_HVAC_STATE: self._client.state,191 }192 @property193 def target_temperature(self):194 """Return the target temperature we try to reach."""195 if self._client.mode == self._client.MODE_HEAT:196 return self._client.heattemp197 if self._client.mode == self._client.MODE_COOL:198 return self._client.cooltemp199 return None200 @property201 def target_temperature_low(self):202 """Return the lower bound temp if auto mode is on."""203 if self._client.mode == self._client.MODE_AUTO:204 return self._client.heattemp205 return None206 @property207 def target_temperature_high(self):208 """Return the upper bound temp if auto mode is on."""209 if self._client.mode == self._client.MODE_AUTO:210 return self._client.cooltemp211 return None212 @property213 def target_humidity(self):214 """Return the humidity we try to reach."""215 return self._client.hum_setpoint216 @property217 def min_humidity(self):218 """Return the minimum humidity. Hardcoded to 0 in API."""219 return 0220 @property221 def max_humidity(self):222 """Return the maximum humidity. Hardcoded to 60 in API."""223 return 60224 @property225 def preset_mode(self):226 """Return current preset."""227 if self._client.away:228 return PRESET_AWAY229 if self._client.schedule == 0:230 return HOLD_MODE_TEMPERATURE231 return PRESET_NONE232 @property233 def preset_modes(self):234 """Return valid preset modes."""235 return [PRESET_NONE, PRESET_AWAY, HOLD_MODE_TEMPERATURE]236 def _set_operation_mode(self, operation_mode):237 """Change the operation mode (internal)."""238 if operation_mode == HVAC_MODE_HEAT:239 success = self._client.set_mode(self._client.MODE_HEAT)240 elif operation_mode == HVAC_MODE_COOL:241 success = self._client.set_mode(self._client.MODE_COOL)242 elif operation_mode == HVAC_MODE_AUTO:243 success = self._client.set_mode(self._client.MODE_AUTO)244 else:245 success = self._client.set_mode(self._client.MODE_OFF)246 if not success:247 _LOGGER.error("Failed to change the operation mode")248 return success249 def set_temperature(self, **kwargs):250 """Set a new target temperature."""251 set_temp = True252 operation_mode = kwargs.get(ATTR_HVAC_MODE)253 temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW)254 temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH)255 temperature = kwargs.get(ATTR_TEMPERATURE)256 if operation_mode and self._mode_map.get(operation_mode) != self._client.mode:257 set_temp = self._set_operation_mode(operation_mode)258 if set_temp:259 if (260 self._mode_map.get(operation_mode, self._client.mode)261 == self._client.MODE_HEAT262 ):263 success = self._client.set_setpoints(temperature, self._client.cooltemp)264 elif (265 self._mode_map.get(operation_mode, self._client.mode)266 == self._client.MODE_COOL267 ):268 success = self._client.set_setpoints(self._client.heattemp, temperature)269 elif (270 self._mode_map.get(operation_mode, self._client.mode)271 == self._client.MODE_AUTO272 ):273 success = self._client.set_setpoints(temp_low, temp_high)274 else:275 success = False276 _LOGGER.error(277 "The thermostat is currently not in a mode "278 "that supports target temperature: %s",279 operation_mode,280 )281 if not success:282 _LOGGER.error("Failed to change the temperature")283 self.schedule_update_ha_state()284 def set_fan_mode(self, fan_mode):285 """Set new target fan mode."""286 if fan_mode == STATE_ON:287 success = self._client.set_fan(self._client.FAN_ON)288 else:289 success = self._client.set_fan(self._client.FAN_AUTO)290 if not success:291 _LOGGER.error("Failed to change the fan mode")292 self.schedule_update_ha_state()293 def set_hvac_mode(self, hvac_mode):294 """Set new target operation mode."""295 self._set_operation_mode(hvac_mode)296 self.schedule_update_ha_state()297 def set_humidity(self, humidity):298 """Set new target humidity."""299 success = self._client.set_hum_setpoint(humidity)300 if not success:301 _LOGGER.error("Failed to change the target humidity level")302 self.schedule_update_ha_state()303 def set_preset_mode(self, preset_mode):304 """Set the hold mode."""305 if preset_mode == PRESET_AWAY:306 success = self._client.set_away(self._client.AWAY_AWAY)307 elif preset_mode == HOLD_MODE_TEMPERATURE:308 success = self._client.set_away(self._client.AWAY_HOME)309 success = success and self._client.set_schedule(0)310 elif preset_mode == PRESET_NONE:311 success = self._client.set_away(self._client.AWAY_HOME)312 success = success and self._client.set_schedule(1)313 else:314 _LOGGER.error("Unknown hold mode: %s", preset_mode)315 success = False316 if not success:317 _LOGGER.error("Failed to change the schedule/hold state")...

Full Screen

Full Screen

LineClient.py

Source:LineClient.py Github

copy

Full Screen

1# -*- coding: utf-8 -*-2from .LineApi import LineApi3from .LineServer import url4from .LineCallback import LineCallback5from ..LineThrift.ttypes import Message6import json, requests, tempfile, shutil7import unicodedata8from random import randint910try:11 from thrift.protocol import fastbinary12except:13 fastbinary = None1415def loggedIn(func):16 def checkLogin(*args, **kwargs):17 if args[0].isLogin:18 return func(*args, **kwargs)19 else:20 args[0].callback.other("you want to call the function, you must login to LINE!!!!!")21 return checkLogin2223class LineClient(LineApi):2425 def __init__(self):26 LineApi.__init__(self)27 self._messageReq = {}28 self._session = requests.session()29 self._headers = url.Headers3031 @loggedIn32 def _loginresult(self):33 if self.isLogin == True:34 print "VodkaBot\n"35 print "authToken : " + self.authToken + "\n"36 print "certificate : " + self.certificate + "\n"37 """:type profile: Profile"""38 profile = self._client.getProfile()39 print "name : " + profile.displayName40 else:41 print "must login!\n"4243 @loggedIn44 def post_content(self, urls, data=None, files=None):45 return self._session.post(urls, headers=self._headers, data=data, files=files)4647 """Image"""4849 @loggedIn50 def sendImage(self, to_, path):51 M = Message(to=to_, text=None, contentType = 1)52 M.contentMetadata = None53 M.contentPreview = None54 M2 = self._client.sendMessage(0,M)55 M_id = M2.id56 files = {57 'file': open(path, 'rb'),58 }59 params = {60 'name': 'media',61 'oid': M_id,62 'size': len(open(path, 'rb').read()),63 'type': 'image',64 'ver': '1.0',65 }66 data = {67 'params': json.dumps(params)68 }69 r = self.post_content('https://obs-sg.line-apps.com/talk/m/upload.nhn', data=data, files=files)70 if r.status_code != 201:71 raise Exception('Upload image failure.')72 return True7374 @loggedIn75 def sendImageWithURL(self, to_, url):76 path = '%s/pythonLine-%i.data' % (tempfile.gettempdir(), randint(0, 9))77 r = requests.get(url, stream=True)78 if r.status_code == 200:79 with open(path, 'w') as f:80 shutil.copyfileobj(r.raw, f)81 else:82 raise Exception('Download image failure.')83 try:84 self.sendImage(to_, path)85 except Exception as e:86 raise e87 """User"""8889 @loggedIn90 def getProfile(self):91 return self._client.getProfile()9293 @loggedIn94 def getSettings(self):95 return self._client.getSettings()9697 @loggedIn98 def getUserTicket(self):99 return self._client.getUserTicket()100101 @loggedIn102 def updateProfile(self, profileObject):103 return self._client.updateProfile(0, profileObject)104105 @loggedIn106 def updateSettings(self, settingObject):107 return self._client.updateSettings(0, settingObject)108109 """Operation"""110111 @loggedIn112 def fetchOperation(self, revision, count):113 return self._client.fetchOperations(revision, count)114115 @loggedIn116 def getLastOpRevision(self):117 return self._client.getLastOpRevision()118119 """Message"""120121 @loggedIn122 def sendEvent(self, messageObject):123 return self._client.sendEvent(0, messageObject)124125 @loggedIn126 def sendMessage(self, messageObject):127 return self._client.sendMessage(0,messageObject)128129 def getLastReadMessageIds(self, chatId):130 return self._client.getLastReadMessageIds(0,chatId)131132 """Image"""133134 @loggedIn135 def post_content(self, url, data=None, files=None):136 return self._session.post(url, headers=self._headers, data=data, files=files)137138 """Contact"""139140 @loggedIn141 def blockContact(self, mid):142 return self._client.blockContact(0, mid)143144 @loggedIn145 def unblockContact(self, mid):146 return self._client.unblockContact(0, mid)147148 @loggedIn149 def findAndAddContactsByMid(self, mid):150 return self._client.findAndAddContactsByMid(0, mid)151152 @loggedIn153 def findAndAddContactsByUserid(self, userid):154 return self._client.findAndAddContactsByUserid(0, userid)155156 @loggedIn157 def findContactsByUserid(self, userid):158 return self._client.findContactByUserid(userid)159160 @loggedIn161 def findContactByTicket(self, ticketId):162 return self._client.findContactByUserTicket(ticketId)163164 @loggedIn165 def getAllContactIds(self):166 return self._client.getAllContactIds()167168 @loggedIn169 def getBlockedContactIds(self):170 return self._client.getBlockedContactIds()171172 @loggedIn173 def getContact(self, mid):174 return self._client.getContact(mid)175176 @loggedIn177 def getContacts(self, midlist):178 return self._client.getContacts(midlist)179180 @loggedIn181 def getFavoriteMids(self):182 return self._client.getFavoriteMids()183184 @loggedIn185 def getHiddenContactMids(self):186 return self._client.getHiddenContactMids()187188189 """Group"""190191 @loggedIn192 def acceptGroupInvitation(self, groupId):193 return self._client.acceptGroupInvitation(0, groupId)194195 @loggedIn196 def acceptGroupInvitationByTicket(self, groupId, ticketId):197 return self._client.acceptGroupInvitationByTicket(0, groupId, ticketId)198199 @loggedIn200 def cancelGroupInvitation(self, groupId, contactIds):201 return self._client.cancelGroupInvitation(0, groupId, contactIds)202203 @loggedIn204 def createGroup(self, name, midlist):205 return self._client.createGroup(0, name, midlist)206207 @loggedIn208 def getGroup(self, groupId):209 return self._client.getGroup(groupId)210211 @loggedIn212 def getGroups(self, groupIds):213 return self._client.getGroups(groupIds)214215 @loggedIn216 def getGroupIdsInvited(self):217 return self._client.getGroupIdsInvited()218219 @loggedIn220 def getGroupIdsJoined(self):221 return self._client.getGroupIdsJoined()222223 @loggedIn224 def inviteIntoGroup(self, groupId, midlist):225 return self._client.inviteIntoGroup(0, groupId, midlist)226227 @loggedIn228 def kickoutFromGroup(self, groupId, midlist):229 return self._client.kickoutFromGroup(0, groupId, midlist)230231 @loggedIn232 def leaveGroup(self, groupId):233 return self._client.leaveGroup(0, groupId)234235 @loggedIn236 def rejectGroupInvitation(self, groupId):237 return self._client.rejectGroupInvitation(0, groupId)238239 @loggedIn240 def reissueGroupTicket(self, groupId):241 return self._client.reissueGroupTicket(groupId)242243 @loggedIn244 def updateGroup(self, groupObject):245 return self._client.updateGroup(0, groupObject)246247 """Room"""248249 @loggedIn250 def createRoom(self, midlist):251 return self._client.createRoom(0, midlist)252253 @loggedIn254 def getRoom(self, roomId):255 return self._client.getRoom(roomId)256257 @loggedIn258 def inviteIntoRoom(self, roomId, midlist):259 return self._client.inviteIntoRoom(0, roomId, midlist)260261 @loggedIn262 def leaveRoom(self, roomId):263 return self._client.leaveRoom(0, roomId)264265 """unknown function"""266267 @loggedIn268 def noop(self): ...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run localstack automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful