Best Python code snippet using localstack_python
Galil_DMC_22x0_NgClient.py
Source:Galil_DMC_22x0_NgClient.py  
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 _:...climate.py
Source:climate.py  
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")...LineClient.py
Source:LineClient.py  
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):
...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.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
