Best Python code snippet using autotest_python
phidget.py
Source:phidget.py
1"""2The following is intended as the south-plugin of Dianomic's windbine demo of FogLAMP. The code uses the following Phidget based sensors: 3 - Temperature & Humidity: HUM1000_0 (https://www.phidgets.com/?tier=3&catid=14&pcid=12&prodid=644)4 - Spatial: MOT1101_0 (https://www.phidgets.com/?tier=3&catid=10&pcid=8&prodid=975)5 - Rotary: 3531_0 (https://www.phidgets.com/?tier=3&catid=103&pcid=83&prodid=404)6 - Current: VCP1100_0 (https://www.phidgets.com/?tier=3&catid=16&pcid=14&prodid=983)7"""8# -*- coding: utf-8 -*-9# FOGLAMP_BEGIN10# See: http://foglamp.readthedocs.io/11# FOGLAMP_END12""" Module for Phidget poll mode plugin """13import copy14import datetime15import logging16import math17import time 18import uuid 19from foglamp.common import logger20from foglamp.plugins.common import utils21from foglamp.services.south import exceptions22from Phidget22.Devices.Accelerometer import *23from Phidget22.Devices.CurrentInput import * 24from Phidget22.Devices.Encoder import *25from Phidget22.Devices.Gyroscope import *26from Phidget22.Devices.HumiditySensor import *27from Phidget22.Devices.Magnetometer import *28from Phidget22.Devices.TemperatureSensor import *29from Phidget22.PhidgetException import *30from Phidget22.Phidget import *31__author__ = "Ori Shadmon" 32__copyright__ = "Copyright (c) 2019 Dianomic Systems"33__license__ = "Apache 2.0"34__version__ = "${VERSION}"35_DEFAULT_CONFIG = {36 'plugin': {37 'description': 'Phidget Poll Plugin',38 'type': 'string',39 'default': 'phidget',40 'readonly': 'true'41 },42 'hubSN': {43 'description': 'VINT Hub Serial Number',44 'type': 'string',45 'default': '538854',46 'order': '1',47 'displayName': 'VINT Hub SN'48 },49 'assetPrefix': {50 'description': 'Prefix of asset name',51 'type': 'string',52 'default': 'phidget/',53 'order': '2',54 'displayName': 'Asset Name Prefix'55 },56 'tempHumAssetName': {57 'description': 'Humidity/Temperature sensor asset name',58 'type': 'string',59 'default': 'weather',60 'order': '3',61 'displayName': 'Humidity/Temperature Asset Name'62 },63 'tempHumPort': {64 'description': 'VINT Hub port of temperature/humidity sensor',65 'type': 'string',66 'default': '0',67 'order': '4',68 'displayName': 'Humidity/Temperature Port'69 },70 'tempHumPoll': {71 'description': 'Obtain Humidity/Temperature every nth time the plugin is pulled', 72 'type': 'integer', 73 'default': '1',74 'order': '5', 75 'displayName': 'Humidity/Temperature Poll', 76 }, 77 'tempHumEnable': {78 'description': 'Enable Humidity/Temperature',79 'type': 'boolean', 80 'default': 'true', 81 'order': '6', 82 'displayName': 'Enable Humidity/Temperature'83 },84 'currentAssetName': {85 'description': 'Current sensor asset name',86 'type': 'string',87 'default': 'current',88 'order': '7',89 'displayName': 'Current Asset Name'90 },91 'currentPort': {92 'description': 'VINT Hub port of current sensor',93 'type': 'string',94 'default': '3',95 'order': '8',96 'displayName': 'Current Port'97 },98 'currentPoll': {99 'description': 'Obtain current every nth time the plugin is pulled', 100 'type': 'integer', 101 'default': '1', 102 'order': '9', 103 'displayName': 'Current Poll'104 },105 'currentEnable': {106 'description': 'Enable/Disable Current sensor', 107 'type': 'boolean',108 'default': 'true', 109 'order': '10', 110 'displayName': 'Enable Current'111 },112 'encoderAssetName': {113 'description': 'Encoder sensor asset name',114 'type': 'string',115 'default': 'encoder',116 'order': '11',117 'displayName': 'Encoder Asset Name'118 },119 'encoderPort': {120 'description': 'VINT Hub port of encoder sensor',121 'type': 'string',122 'default': '1',123 'order': '12',124 'displayName': 'Encoder Port'125 },126 'encoderPoll': {127 'description': 'Obtain encoder every nth time the plugin is pulled',128 'type': 'integer',129 'default': '1',130 'order': '13',131 'displayName': 'Encoder Poll'132 },133 'encoderEnable': {134 'description': 'Enable Encoder Sensor',135 'type': 'boolean',136 'default': 'true',137 'order': '14',138 'displayName': 'Enable Encoder'139 },140 'spatialPort': {141 'description': 'VINT Hub port of spatial sensors', 142 'type': 'string', 143 'default': '2', 144 'order': '15', 145 'displayName': 'Spatial Port'146 },147 'accelerometerAssetName': {148 'description': 'accelerometer sensor asset name',149 'type': 'string',150 'default': 'accelerometer',151 'order': '16',152 'displayName': 'accelerometer Asset Name'153 },154 'accelerometerPoll': {155 'description': 'Obtain accelerometer every nth time the plugin is pulled',156 'type': 'integer',157 'default': '1',158 'order': '17',159 'displayName': 'Acceleration Poll'160 },161 'accelerometerEnable': {162 'description': 'Enable Acceleration Sensor',163 'type': 'boolean',164 'default': 'true',165 'order': '18',166 'displayName': 'Acceleration Encoder'167 },168 'gyroscopeAssetName': {169 'description': 'gyroscope sensor asset name',170 'type': 'string',171 'default': 'gyroscope',172 'order': '19',173 'displayName': 'gyroscope Asset Name'174 },175 'gyroscopePoll': {176 'description': 'Obtain gyroscope every nth time the plugin is pulled',177 'type': 'integer',178 'default': '1',179 'order': '20',180 'displayName': 'Gyroscope Poll'181 },182 'gyroscopeEnable': {183 'description': 'Enable Gyroscope Sensor',184 'type': 'boolean',185 'default': 'true',186 'order': '21',187 'displayName': 'Enable Gyroscope'188 },189 'magnetometerAssetName': {190 'description': 'magnetometer sensor asset name',191 'type': 'string',192 'default': 'magnetometer',193 'order': '22',194 'displayName': 'magnetometer Asset Name'195 },196 'magnetometerPoll': {197 'description': 'Obtain magnetometer every nth time the plugin is pulled',198 'type': 'integer',199 'default': '1',200 'order': '23',201 'displayName': 'Magnetometer Poll'202 },203 'magnetometerEnable': {204 'description': 'Enable Magnetometer Sensor',205 'type': 'boolean',206 'default': 'true',207 'order': '24',208 'displayName': 'Enable Magnetometer'209 }210}211_LOGGER = logger.setup(__name__, level=logging.INFO)212def plugin_info():213 """ Returns information about the plugin.214 Args:215 Returns:216 dict: plugin information217 Raises:218 """219 return {220 'name': 'Phidget Poll Plugin',221 'version': '2.0.0',222 'mode': 'poll',223 'type': 'south',224 'interface': '1.0',225 'config': _DEFAULT_CONFIG226 }227def plugin_init(config):228 """ Initialise the plugin.229 Args:230 config: JSON configuration document for the South plugin configuration category231 Returns:232 data: JSON object to be used in future calls to the plugin233 Raises:234 """235 try: 236 data = copy.deepcopy(config)237 if data['tempHumEnable']['value'] == 'true':238 data['humidity'] = HumiditySensor()239 data['humidity'].setDeviceSerialNumber(int(data['hubSN']['value']))240 data['humidity'].setHubPort(int(data['tempHumPort']['value']))241 data['humidity'].setIsHubPortDevice(False)242 data['humidity'].setChannel(0)243 data['humidity'].openWaitForAttachment(5000)244 try:245 data['humidity'].getHumidity()246 except Exception as e:247 pass248 data['temperature'] = TemperatureSensor() 249 data['temperature'].setDeviceSerialNumber(int(data['hubSN']['value']))250 data['temperature'].setHubPort(int(data['tempHumPort']['value']))251 data['temperature'].setIsHubPortDevice(False)252 data['temperature'].setChannel(0)253 data['temperature'].openWaitForAttachment(5000)254 try:255 data['temperature'].getTemperature()256 except Exception as e:257 pass258 if data['currentEnable']['value'] == 'true': 259 data['current'] = CurrentInput() 260 data['current'].setDeviceSerialNumber(int(data['hubSN']['value']))261 data['current'].setHubPort(int(data['currentPort']['value']))262 data['current'].setIsHubPortDevice(False)263 data['current'].setChannel(0)264 data['current'].openWaitForAttachment(5000)265 try:266 data['current'].getCurrent()267 except Exception as e:268 pass269 if data['encoderEnable']['value'] == 'true': 270 data['encoder'] = Encoder()271 data['encoder'].setDeviceSerialNumber(int(data['hubSN']['value']))272 data['encoder'].setHubPort(int(data['encoderPort']['value']))273 data['encoder'].setIsHubPortDevice(False)274 data['encoder'].setChannel(0)275 data['encoder'].openWaitForAttachment(5000)276 data['encoder'].setDataInterval(20)277 i = 0278 while i < 120:279 try:280 data['encoder'].getPosition()281 except Exception as e:282 time.sleep(1)283 i+=1284 else:285 break286 287 if data['accelerometerEnable']['value'] == 'true': 288 data['accelerometer'] = Accelerometer()289 data['accelerometer'].setDeviceSerialNumber(int(data['hubSN']['value']))290 data['accelerometer'].setHubPort(int(data['spatialPort']['value']))291 data['accelerometer'].setIsHubPortDevice(False)292 data['accelerometer'].setChannel(0)293 data['accelerometer'].openWaitForAttachment(5000)294 data['accelerometer'].setDataInterval(20)295 i = 0296 while i < 120:297 try:298 data['accelerometer'].getAcceleration()299 except Exception as e:300 time.sleep(1)301 i+=1302 else:303 break304 if data['gyroscopeEnable']['value'] == 'true': 305 data['gyroscope'] = Gyroscope()306 data['gyroscope'].setDeviceSerialNumber(int(data['hubSN']['value']))307 data['gyroscope'].setHubPort(int(data['spatialPort']['value']))308 data['gyroscope'].setIsHubPortDevice(False)309 data['gyroscope'].setChannel(0)310 data['gyroscope'].openWaitForAttachment(5000)311 data['gyroscope'].setDataInterval(20)312 i = 0313 while i < 120:314 try:315 data['gyroscope'].getAngularRate()316 except Exception as e:317 time.sleep(1)318 i+=1319 else:320 break321 if data['magnetometerEnable']['value'] == 'true': 322 data['magnetometer'] = Magnetometer()323 data['magnetometer'].setDeviceSerialNumber(int(data['hubSN']['value']))324 data['magnetometer'].setHubPort(int(data['spatialPort']['value']))325 data['magnetometer'].setIsHubPortDevice(False)326 data['magnetometer'].setChannel(0)327 data['magnetometer'].openWaitForAttachment(5000)328 data['magnetometer'].setDataInterval(20)329 i = 0 330 while i < 120: 331 try: 332 data['magnetometer'].getMagneticField() 333 except Exception as e: 334 time.sleep(1)335 i+=1336 else: 337 break 338 except Exception as ex:339 _LOGGER.exception("Phidget exception: {}".format(str(ex)))340 raise ex341 # counter to know when to run process 342 data['tempHumCount'] = 0 343 data['currentCount'] = 0 344 data['encoderCount'] = 0 345 data['accelerometerCount'] = 0 346 data['gyroscopeCount'] = 0 347 data['magnetometerCount'] = 0 348 # counter of last encoder value 349 data['encoderPreviousValue'] = 0 350 data['encoderPreviousTime'] = 0 351 return data352def plugin_poll(handle):353 """ Extracts data from the sensor and returns it in a JSON document as a Python dict.354 Available for poll mode only.355 Args:356 handle: handle returned by the plugin initialisation call357 Returns:358 returns a sensor reading in a JSON document, as a Python dict, if it is available359 None - If no reading is available360 Raises:361 TimeoutError362 """363 # air quality is votlage reading between 0 and 5.1364 # we scale is to a value between 0 and 1023365 try:366 time_stamp = utils.local_timestamp()367 data = list()368 if (handle['tempHumEnable']['value'] == 'true' and handle['tempHumCount'] == 0): 369 data.append({370 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['tempHumAssetName']['value']),371 'timestamp': time_stamp,372 'key': str(uuid.uuid4()),373 'readings': {374 "temperature": handle['temperature'].getTemperature(),375 "humidity": handle['humidity'].getHumidity()376 } 377 })378 if (handle['currentEnable']['value'] == 'true' and handle['currentCount'] == 0): 379 data.append({380 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['currentAssetName']['value']),381 'timestamp': time_stamp,382 'key': str(uuid.uuid4()),383 'readings': {384 "current": handle['current'].getCurrent()385 }386 })387 if (handle['encoderEnable']['value'] == 'true' and handle['encoderCount'] == 0):388 value = handle['encoder'].getPosition()389 if handle['encoderPreviousValue'] > 0: # ommit first one390 # convert to datetime type 391 if ":" == time_stamp[-3:-2]: 392 timestamp_new = datetime.datetime.strptime(time_stamp[:-3]+time_stamp[-2:], '%Y-%m-%d %H:%M:%S.%f%z') 393 394 if ":" == handle['encoderPreviousTime'][-3:-2]: 395 timestamp_old = datetime.datetime.strptime(handle['encoderPreviousTime'][:-3]+handle['encoderPreviousTime'][-2:], '%Y-%m-%d %H:%M:%S.%f%z')396 397 # calculate elapse time in milliseconds 398 elapse_time = timestamp_new - timestamp_old 399 elapse_time = elapse_time.total_seconds() 400 data.append({401 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['encoderAssetName']['value']),402 'timestamp': time_stamp,403 'key': str(uuid.uuid4()),404 'readings': {405 # (current_total_iterations - previous_total_iterations)/1200) / (elapsed time in milliseconds) 406 "rotation-since-last-call": (value - handle['encoderPreviousValue'])/1200,407 "rotation-per-second": (value - handle['encoderPreviousValue'])/elapse_time408 }409 })410 handle['encoderPreviousValue'] = value 411 handle['encoderPreviousTime'] = time_stamp412 if (handle['accelerometerEnable']['value'] == 'true' and handle['accelerometerCount'] == 0):413 x, y, z = handle['accelerometer'].getAcceleration()414 data.append({415 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['accelerometerAssetName']['value']),416 'timestamp': time_stamp,417 'key': str(uuid.uuid4()),418 'readings': {419 "accelerometer-x": x,420 "accelerometer-y": y, 421 "accelerometer-z": z422 }423 })424 if (handle['gyroscopeEnable']['value'] == 'true' and handle['gyroscopeCount'] == 0): 425 x, y, z = handle['gyroscope'].getAngularRate()426 data.append({427 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['gyroscopeAssetName']['value']),428 'timestamp': time_stamp,429 'key': str(uuid.uuid4()),430 'readings': {431 "gyroscope-x": x,432 "gyroscope-y": y,433 "gyroscope-z": z434 }435 })436 if (handle['magnetometerEnable']['value'] == 'true' and handle['magnetometerCount'] == 0):437 x, y, z = handle['magnetometer'].getMagneticField()438 data.append({439 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['magnetometerAssetName']['value']),440 'timestamp': time_stamp,441 'key': str(uuid.uuid4()),442 'readings': {443 "magnetometer-x": x,444 "magnetometer-y": y,445 "magnetometer-z": z446 } 447 })448 handle['tempHumCount'] = (handle['tempHumCount'] + 1) % int(handle['tempHumPoll']['value'])449 handle['currentCount'] = (handle['currentCount'] + 1) % int(handle['currentPoll']['value']) 450 handle['encoderCount'] = (handle['encoderCount'] + 1) % int(handle['encoderPoll']['value']) 451 handle['accelerometerCount'] = (handle['accelerometerCount'] + 1) % int(handle['accelerometerPoll']['value'])452 handle['gyroscopeCount'] = (handle['gyroscopeCount'] + 1) % int(handle['gyroscopePoll']['value'])453 handle['magnetometerCount'] = (handle['magnetometerCount'] + 1) % int(handle['magnetometerPoll']['value'])454 except (Exception, RuntimeError) as ex:455 _LOGGER.exception("Phidget exception: {}".format(str(ex)))456 raise exceptions.DataRetrievalError(ex)457 else:458 return data459def plugin_reconfigure(handle, new_config):460 """ Reconfigures the plugin461 Args:462 handle: handle returned by the plugin initialisation call463 new_config: JSON object representing the new configuration category for the category464 Returns:465 new_handle: new handle to be used in the future calls466 """467 _LOGGER.info("Old config for Phidget plugin {} \n new config {}".format(handle, new_config))468 # Shutdown sensors 469 try: 470 handle['humidity'].close() 471 handle['temperature'].close()472 handle['current'].close() 473 handle['encoder'].close() 474 handle['accelerometer'].close() 475 handle['gyroscope'].close() 476 handle['magnetometer'].close() 477 except Exception as ex:478 _LOGGER.exception("Phidget exception: {}".format(str(ex)))479 raise ex480 time.sleep(5) 481 new_handle = copy.deepcopy(new_config)482 try: 483 # check if temp/humidity sensor is enabled. If so restart it 484 if new_handle['tempHumEnable']['value'] == 'true': 485 new_handle['humidity'] = HumiditySensor()486 new_handle['humidity'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))487 new_handle['humidity'].setHubPort(int(new_handle['tempHumPort']['value']))488 new_handle['humidity'].setIsHubPortDevice(False)489 new_handle['humidity'].setChannel(0)490 new_handle['humidity'].openWaitForAttachment(5000)491 try:492 new_handle['humidity'].getHumidity()493 except Exception as e:494 pass495 new_handle['temperature'] = TemperatureSensor()496 new_handle['temperature'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))497 new_handle['temperature'].setHubPort(int(new_handle['tempHumPort']['value']))498 new_handle['temperature'].setIsHubPortDevice(False)499 new_handle['temperature'].setChannel(0)500 new_handle['temperature'].openWaitForAttachment(5000)501 try:502 new_handle['temperature'].getTemperature()503 except Exception as e:504 pass505 # check if current sensor is enabled, if so restart it 506 if new_handle['currentEnable']['value'] == 'true':507 new_handle['current'] = CurrentInput()508 new_handle['current'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))509 new_handle['current'].setHubPort(int(new_handle['currentPort']['value']))510 new_handle['current'].setIsHubPortDevice(False)511 new_handle['current'].setChannel(0)512 new_handle['current'].openWaitForAttachment(5000)513 try:514 new_handle['current'].getCurrent()515 except Exception as e:516 pass517 # check if encoder sensor is enabled 518 if new_handle['encoderEnable']['value'] == 'true':519 new_handle['encoder'] = Encoder()520 new_handle['encoder'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))521 new_handle['encoder'].setHubPort(int(new_handle['encoderPort']['value']))522 new_handle['encoder'].setIsHubPortDevice(False)523 new_handle['encoder'].setChannel(0)524 new_handle['encoder'].openWaitForAttachment(5000)525 new_handle['encoder'].setDataInterval(20)526 i = 0527 while i < 120:528 try:529 new_handle['encoder'].getPosition()530 except Exception as e:531 time.sleep(1)532 i+=1533 else:534 break535 # check if accelerometer is enabled536 if new_handle['accelerometerEnable']['value'] == 'true':537 new_handle['accelerometer'] = Accelerometer()538 new_handle['accelerometer'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))539 new_handle['accelerometer'].setHubPort(int(new_handle['spatialPort']['value']))540 new_handle['accelerometer'].setIsHubPortDevice(False)541 new_handle['accelerometer'].setChannel(0)542 new_handle['accelerometer'].openWaitForAttachment(5000)543 new_handle['accelerometer'].setDataInterval(20)544 i = 0545 while i < 120:546 try:547 new_handle['accelerometer'].getAcceleration()548 except Exception as e:549 time.sleep(1)550 i+=1551 else:552 break553 # check if gyroscope is enabled 554 if new_handle['gyroscopeEnable']['value'] == 'true':555 new_handle['gyroscope'] = Gyroscope()556 new_handle['gyroscope'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))557 new_handle['gyroscope'].setHubPort(int(new_handle['spatialPort']['value']))558 new_handle['gyroscope'].setIsHubPortDevice(False)559 new_handle['gyroscope'].setChannel(0)560 new_handle['gyroscope'].openWaitForAttachment(5000)561 new_handle['gyroscope'].setDataInterval(20)562 i = 0563 while i < 120:564 try:565 new_handle['gyroscope'].getAngularRate()566 except Exception as e:567 time.sleep(1)568 i+=1569 else:570 break571 # check if magnetometer enable is enabled 572 if new_handle['magnetometerEnable']['value'] == 'true':573 new_handle['magnetometer'] = Magnetometer()574 new_handle['magnetometer'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))575 new_handle['magnetometer'].setHubPort(int(new_handle['spatialPort']['value']))576 new_handle['magnetometer'].setIsHubPortDevice(False)577 new_handle['magnetometer'].setChannel(0)578 new_handle['magnetometer'].openWaitForAttachment(5000)579 new_handle['magnetometer'].setDataInterval(20)580 i = 0581 while i < 120:582 try:583 new_handle['magnetometer'].getMagneticField()584 except Exception as e:585 time.sleep(1)586 i+=1587 else:588 break589 # check if hub has changed, if so init restart 590 if new_handle['hubSN']['value'] != handle['hubSN']['value']:591 new_handle['restart'] = 'yes'592 else:593 new_handle['restart'] = 'no'594 except Exception as ex:595 _LOGGER.exception("Phidget exception: {}".format(str(ex)))596 raise ex597 # counter to know when to run process598 new_handle['tempHumCount'] = 0599 new_handle['currentCount'] = 0600 new_handle['encoderCount'] = 0601 new_handle['accelerometerCount'] = 0602 new_handle['gyroscopeCount'] = 0603 new_handle['magnetometerCount'] = 0604 # counter of last encoder value605 new_handle['encoderPreviousValue'] = handle['encoderPreviousValue']606 return new_handle607def plugin_shutdown(handle):608 """ Shutdowns the plugin doing required cleanup, to be called prior to the South plugin service being shut down.609 Args:610 handle: handle returned by the plugin initialisation call611 Returns:612 plugin shutdown613 """614 try:615 handle['humidity'].close()616 handle['temperature'].close()617 handle['current'].close()618 handle['encoder'].close()619 handle['accelerometer'].close()620 handle['gyroscope'].close()621 handle['magnetometer'].close()622 except Exception as ex:623 _LOGGER.exception("Phidget exception: {}".format(str(ex)))624 raise ex...
wind_turbine.py
Source:wind_turbine.py
1# -*- coding: utf-8 -*-2# FOGLAMP_BEGIN3# See: http://foglamp.readthedocs.io/4# FOGLAMP_END5""" Module for Phidget poll mode plugin6 The following is intended as the south service plugin of Dianomic wind turbine demo of FogLAMP.7 Phidget based sensors:8 - Temperature & Humidity: HUM1000_0 (https://www.phidgets.com/?tier=3&catid=14&pcid=12&prodid=644)9 - Spatial: MOT1101_0 (https://www.phidgets.com/?tier=3&catid=10&pcid=8&prodid=975)10 - Rotary: 3531_0 (https://www.phidgets.com/?tier=3&catid=103&pcid=83&prodid=404)11 - Current: VCP1100_0 (https://www.phidgets.com/?tier=3&catid=16&pcid=14&prodid=983)12"""13import copy14import datetime15import logging16import math17import time 18from foglamp.common import logger19from foglamp.plugins.common import utils20from foglamp.services.south import exceptions21from Phidget22.Devices.Accelerometer import *22from Phidget22.Devices.CurrentInput import * 23from Phidget22.Devices.Encoder import *24from Phidget22.Devices.Gyroscope import *25from Phidget22.Devices.HumiditySensor import *26from Phidget22.Devices.Magnetometer import *27from Phidget22.Devices.TemperatureSensor import *28from Phidget22.PhidgetException import *29from Phidget22.Phidget import *30__author__ = "Ori Shadmon" 31__copyright__ = "Copyright (c) 2019 Dianomic Systems Inc."32__license__ = "Apache 2.0"33__version__ = "${VERSION}"34_DEFAULT_CONFIG = {35 'plugin': {36 'description': 'Wind Turbine Poll Plugin',37 'type': 'string',38 'default': 'wind_turbine',39 'readonly': 'true'40 },41 'hubSN': {42 'description': 'VINT Hub Serial Number',43 'type': 'string',44 'default': '538854',45 'order': '1',46 'displayName': 'VINT Hub SN'47 },48 'assetPrefix': {49 'description': 'Prefix of asset name',50 'type': 'string',51 'default': 'wind_turbine/',52 'order': '2',53 'displayName': 'Asset Name Prefix'54 },55 'tempHumAssetName': {56 'description': 'Humidity/Temperature sensor asset name',57 'type': 'string',58 'default': 'weather',59 'order': '3',60 'displayName': 'Humidity/Temperature Asset Name'61 },62 'tempHumPort': {63 'description': 'VINT Hub port of temperature/humidity sensor',64 'type': 'string',65 'default': '0',66 'order': '4',67 'displayName': 'Humidity/Temperature Port'68 },69 'tempHumPoll': {70 'description': 'Obtain Humidity/Temperature every nth time the plugin is pulled', 71 'type': 'integer', 72 'default': '1',73 'order': '5', 74 'displayName': 'Humidity/Temperature Poll', 75 }, 76 'tempHumEnable': {77 'description': 'Enable Humidity/Temperature',78 'type': 'boolean', 79 'default': 'true', 80 'order': '6', 81 'displayName': 'Enable Humidity/Temperature'82 },83 'currentAssetName': {84 'description': 'Current sensor asset name',85 'type': 'string',86 'default': 'current',87 'order': '7',88 'displayName': 'Current Asset Name'89 },90 'currentPort': {91 'description': 'VINT Hub port of current sensor',92 'type': 'string',93 'default': '3',94 'order': '8',95 'displayName': 'Current Port'96 },97 'currentPoll': {98 'description': 'Obtain current every nth time the plugin is pulled', 99 'type': 'integer', 100 'default': '1', 101 'order': '9', 102 'displayName': 'Current Poll'103 },104 'currentEnable': {105 'description': 'Enable/Disable Current sensor', 106 'type': 'boolean',107 'default': 'true', 108 'order': '10', 109 'displayName': 'Enable Current'110 },111 'encoderAssetName': {112 'description': 'Encoder sensor asset name',113 'type': 'string',114 'default': 'encoder',115 'order': '11',116 'displayName': 'Encoder Asset Name'117 },118 'encoderPort': {119 'description': 'VINT Hub port of encoder sensor',120 'type': 'string',121 'default': '1',122 'order': '12',123 'displayName': 'Encoder Port'124 },125 'encoderPoll': {126 'description': 'Obtain encoder every nth time the plugin is pulled',127 'type': 'integer',128 'default': '1',129 'order': '13',130 'displayName': 'Encoder Poll'131 },132 'encoderEnable': {133 'description': 'Enable Encoder Sensor',134 'type': 'boolean',135 'default': 'true',136 'order': '14',137 'displayName': 'Enable Encoder'138 },139 'spatialPort': {140 'description': 'VINT Hub port of spatial sensors', 141 'type': 'string', 142 'default': '2', 143 'order': '15', 144 'displayName': 'Spatial Port'145 },146 'accelerometerAssetName': {147 'description': 'accelerometer sensor asset name',148 'type': 'string',149 'default': 'accelerometer',150 'order': '16',151 'displayName': 'accelerometer Asset Name'152 },153 'accelerometerPoll': {154 'description': 'Obtain accelerometer every nth time the plugin is pulled',155 'type': 'integer',156 'default': '1',157 'order': '17',158 'displayName': 'Acceleration Poll'159 },160 'accelerometerEnable': {161 'description': 'Enable Acceleration Sensor',162 'type': 'boolean',163 'default': 'true',164 'order': '18',165 'displayName': 'Acceleration Encoder'166 },167 'gyroscopeAssetName': {168 'description': 'gyroscope sensor asset name',169 'type': 'string',170 'default': 'gyroscope',171 'order': '19',172 'displayName': 'gyroscope Asset Name'173 },174 'gyroscopePoll': {175 'description': 'Obtain gyroscope every nth time the plugin is pulled',176 'type': 'integer',177 'default': '1',178 'order': '20',179 'displayName': 'Gyroscope Poll'180 },181 'gyroscopeEnable': {182 'description': 'Enable Gyroscope Sensor',183 'type': 'boolean',184 'default': 'true',185 'order': '21',186 'displayName': 'Enable Gyroscope'187 },188 'magnetometerAssetName': {189 'description': 'magnetometer sensor asset name',190 'type': 'string',191 'default': 'magnetometer',192 'order': '22',193 'displayName': 'magnetometer Asset Name'194 },195 'magnetometerPoll': {196 'description': 'Obtain magnetometer every nth time the plugin is pulled',197 'type': 'integer',198 'default': '1',199 'order': '23',200 'displayName': 'Magnetometer Poll'201 },202 'magnetometerEnable': {203 'description': 'Enable Magnetometer Sensor',204 'type': 'boolean',205 'default': 'true',206 'order': '24',207 'displayName': 'Enable Magnetometer'208 }209}210_LOGGER = logger.setup(__name__, level=logging.INFO)211def plugin_info():212 """ Returns information about the plugin.213 Args:214 Returns:215 dict: plugin information216 Raises:217 """218 return {219 'name': 'wind_turbine Poll Plugin',220 'version': '1.7.0',221 'mode': 'poll',222 'type': 'south',223 'interface': '1.0',224 'config': _DEFAULT_CONFIG225 }226def plugin_init(config):227 """ Initialise the plugin.228 Args:229 config: JSON configuration document for the South plugin configuration category230 Returns:231 data: JSON object to be used in future calls to the plugin232 Raises:233 """234 try: 235 data = copy.deepcopy(config)236 if data['tempHumEnable']['value'] == 'true':237 data['humidity'] = HumiditySensor()238 data['humidity'].setDeviceSerialNumber(int(data['hubSN']['value']))239 data['humidity'].setHubPort(int(data['tempHumPort']['value']))240 data['humidity'].setIsHubPortDevice(False)241 data['humidity'].setChannel(0)242 data['humidity'].openWaitForAttachment(5000)243 try:244 data['humidity'].getHumidity()245 except Exception:246 pass247 data['temperature'] = TemperatureSensor() 248 data['temperature'].setDeviceSerialNumber(int(data['hubSN']['value']))249 data['temperature'].setHubPort(int(data['tempHumPort']['value']))250 data['temperature'].setIsHubPortDevice(False)251 data['temperature'].setChannel(0)252 data['temperature'].openWaitForAttachment(5000)253 try:254 data['temperature'].getTemperature()255 except Exception:256 pass257 if data['currentEnable']['value'] == 'true': 258 data['current'] = CurrentInput() 259 data['current'].setDeviceSerialNumber(int(data['hubSN']['value']))260 data['current'].setHubPort(int(data['currentPort']['value']))261 data['current'].setIsHubPortDevice(False)262 data['current'].setChannel(0)263 data['current'].openWaitForAttachment(5000)264 try:265 data['current'].getCurrent()266 except Exception:267 pass268 if data['encoderEnable']['value'] == 'true': 269 data['encoder'] = Encoder()270 data['encoder'].setDeviceSerialNumber(int(data['hubSN']['value']))271 data['encoder'].setHubPort(int(data['encoderPort']['value']))272 data['encoder'].setIsHubPortDevice(False)273 data['encoder'].setChannel(0)274 data['encoder'].openWaitForAttachment(5000)275 data['encoder'].setDataInterval(20)276 i = 0277 while i < 120:278 try:279 data['encoder'].getPosition()280 except Exception:281 time.sleep(1)282 i += 1283 else:284 break285 286 if data['accelerometerEnable']['value'] == 'true': 287 data['accelerometer'] = Accelerometer()288 data['accelerometer'].setDeviceSerialNumber(int(data['hubSN']['value']))289 data['accelerometer'].setHubPort(int(data['spatialPort']['value']))290 data['accelerometer'].setIsHubPortDevice(False)291 data['accelerometer'].setChannel(0)292 data['accelerometer'].openWaitForAttachment(5000)293 data['accelerometer'].setDataInterval(20)294 i = 0295 while i < 120:296 try:297 data['accelerometer'].getAcceleration()298 except Exception:299 time.sleep(1)300 i += 1301 else:302 break303 if data['gyroscopeEnable']['value'] == 'true': 304 data['gyroscope'] = Gyroscope()305 data['gyroscope'].setDeviceSerialNumber(int(data['hubSN']['value']))306 data['gyroscope'].setHubPort(int(data['spatialPort']['value']))307 data['gyroscope'].setIsHubPortDevice(False)308 data['gyroscope'].setChannel(0)309 data['gyroscope'].openWaitForAttachment(5000)310 data['gyroscope'].setDataInterval(20)311 i = 0312 while i < 120:313 try:314 data['gyroscope'].getAngularRate()315 except Exception:316 time.sleep(1)317 i += 1318 else:319 break320 if data['magnetometerEnable']['value'] == 'true': 321 data['magnetometer'] = Magnetometer()322 data['magnetometer'].setDeviceSerialNumber(int(data['hubSN']['value']))323 data['magnetometer'].setHubPort(int(data['spatialPort']['value']))324 data['magnetometer'].setIsHubPortDevice(False)325 data['magnetometer'].setChannel(0)326 data['magnetometer'].openWaitForAttachment(5000)327 data['magnetometer'].setDataInterval(20)328 i = 0 329 while i < 120: 330 try: 331 data['magnetometer'].getMagneticField() 332 except Exception:333 time.sleep(1)334 i += 1335 else: 336 break 337 except Exception as ex:338 _LOGGER.exception("wind_turbine exception: {}".format(str(ex)))339 raise ex340 # counter to know when to run process 341 data['tempHumCount'] = 0 342 data['currentCount'] = 0 343 data['encoderCount'] = 0 344 data['accelerometerCount'] = 0 345 data['gyroscopeCount'] = 0 346 data['magnetometerCount'] = 0 347 # counter of last encoder value 348 data['encoderPreviousValue'] = 0349 data['encoderPreviousTime'] = 0 350 return data351def plugin_poll(handle):352 """ Extracts data from the sensor and returns it in a JSON document as a Python dict.353 Available for poll mode only.354 Args:355 handle: handle returned by the plugin initialisation call356 Returns:357 returns a sensor reading in a JSON document, as a Python dict, if it is available358 None - If no reading is available359 Raises:360 TimeoutError361 """362 # air quality is voltage reading between 0 and 5.1363 # we scale is to a value between 0 and 1023364 try:365 time_stamp = utils.local_timestamp()366 data = list()367 if handle['tempHumEnable']['value'] == 'true' and handle['tempHumCount'] == 0:368 data.append({369 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['tempHumAssetName']['value']),370 'timestamp': time_stamp,371 'readings': {372 "temperature": handle['temperature'].getTemperature(),373 "humidity": handle['humidity'].getHumidity()374 } 375 })376 if handle['currentEnable']['value'] == 'true' and handle['currentCount'] == 0:377 data.append({378 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['currentAssetName']['value']),379 'timestamp': time_stamp,380 'readings': {381 "current": handle['current'].getCurrent()382 }383 })384 if handle['encoderEnable']['value'] == 'true' and handle['encoderCount'] == 0:385 value = handle['encoder'].getPosition()386 # convert time_stamp to be usable387 if ":" == time_stamp[-3:-2]:388 timestamp_new = datetime.datetime.strptime(time_stamp[:-3]+time_stamp[-2:], '%Y-%m-%d %H:%M:%S.%f%z')389 else: 390 timestamp_new = datetime.datetime.strptime(time_stamp, '%Y-%m-%d %H:%M:%S.%f%z')391 if handle['encoderPreviousValue'] > 0: # omit first one392 # calculate elapse time in milliseconds393 elapse_time = timestamp_new - handle['encoderPreviousTime']394 elapse_time = elapse_time.total_seconds()395 data.append({396 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['encoderAssetName']['value']),397 'timestamp': time_stamp,398 'readings': {399 # (current_total_iterations - previous_total_iterations) / (elapsed time in seconds) 400 "rotation-per-second": ((value - handle['encoderPreviousValue'])/1200)/elapse_time 401 }402 })403 # update old values 404 handle['encoderPreviousValue'] = value 405 handle['encoderPreviousTime'] = timestamp_new 406 if handle['accelerometerEnable']['value'] == 'true' and handle['accelerometerCount'] == 0:407 x, y, z = handle['accelerometer'].getAcceleration()408 data.append({409 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['accelerometerAssetName']['value']),410 'timestamp': time_stamp,411 'readings': {412 "accelerometer-x": x,413 "accelerometer-y": y, 414 "accelerometer-z": z415 }416 })417 if handle['gyroscopeEnable']['value'] == 'true' and handle['gyroscopeCount'] == 0:418 x, y, z = handle['gyroscope'].getAngularRate()419 data.append({420 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['gyroscopeAssetName']['value']),421 'timestamp': time_stamp,422 'readings': {423 "gyroscope-x": x,424 "gyroscope-y": y,425 "gyroscope-z": z426 }427 })428 if handle['magnetometerEnable']['value'] == 'true' and handle['magnetometerCount'] == 0:429 x, y, z = handle['magnetometer'].getMagneticField()430 data.append({431 'asset': '{}{}'.format(handle['assetPrefix']['value'], handle['magnetometerAssetName']['value']),432 'timestamp': time_stamp,433 'readings': {434 "magnetometer-x": x,435 "magnetometer-y": y,436 "magnetometer-z": z437 } 438 })439 handle['tempHumCount'] = (handle['tempHumCount'] + 1) % int(handle['tempHumPoll']['value'])440 handle['currentCount'] = (handle['currentCount'] + 1) % int(handle['currentPoll']['value']) 441 handle['encoderCount'] = (handle['encoderCount'] + 1) % int(handle['encoderPoll']['value']) 442 handle['accelerometerCount'] = (handle['accelerometerCount'] + 1) % int(handle['accelerometerPoll']['value'])443 handle['gyroscopeCount'] = (handle['gyroscopeCount'] + 1) % int(handle['gyroscopePoll']['value'])444 handle['magnetometerCount'] = (handle['magnetometerCount'] + 1) % int(handle['magnetometerPoll']['value'])445 except (Exception, RuntimeError) as ex:446 _LOGGER.exception("wind_turbine exception: {}".format(str(ex)))447 raise exceptions.DataRetrievalError(ex)448 else:449 return data450def plugin_reconfigure(handle, new_config):451 """ Reconfigures the plugin452 Args:453 handle: handle returned by the plugin initialisation call454 new_config: JSON object representing the new configuration category for the category455 Returns:456 new_handle: new handle to be used in the future calls457 """458 _LOGGER.info("Old config for wind_turbine plugin {} \n new config {}".format(handle, new_config))459 # Shutdown sensors 460 try: 461 handle['humidity'].close() 462 handle['temperature'].close()463 handle['current'].close() 464 handle['encoder'].close() 465 handle['accelerometer'].close() 466 handle['gyroscope'].close() 467 handle['magnetometer'].close() 468 except Exception as ex:469 _LOGGER.exception("wind_turbine exception: {}".format(str(ex)))470 raise ex471 time.sleep(5) 472 new_handle = copy.deepcopy(new_config)473 try: 474 # check if temp/humidity sensor is enabled. If so restart it 475 if new_handle['tempHumEnable']['value'] == 'true': 476 new_handle['humidity'] = HumiditySensor()477 new_handle['humidity'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))478 new_handle['humidity'].setHubPort(int(new_handle['tempHumPort']['value']))479 new_handle['humidity'].setIsHubPortDevice(False)480 new_handle['humidity'].setChannel(0)481 new_handle['humidity'].openWaitForAttachment(5000)482 try:483 new_handle['humidity'].getHumidity()484 except Exception:485 pass486 new_handle['temperature'] = TemperatureSensor()487 new_handle['temperature'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))488 new_handle['temperature'].setHubPort(int(new_handle['tempHumPort']['value']))489 new_handle['temperature'].setIsHubPortDevice(False)490 new_handle['temperature'].setChannel(0)491 new_handle['temperature'].openWaitForAttachment(5000)492 try:493 new_handle['temperature'].getTemperature()494 except Exception:495 pass496 # check if current sensor is enabled, if so restart it 497 if new_handle['currentEnable']['value'] == 'true':498 new_handle['current'] = CurrentInput()499 new_handle['current'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))500 new_handle['current'].setHubPort(int(new_handle['currentPort']['value']))501 new_handle['current'].setIsHubPortDevice(False)502 new_handle['current'].setChannel(0)503 new_handle['current'].openWaitForAttachment(5000)504 try:505 new_handle['current'].getCurrent()506 except Exception:507 pass508 # check if encoder sensor is enabled 509 if new_handle['encoderEnable']['value'] == 'true':510 new_handle['encoder'] = Encoder()511 new_handle['encoder'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))512 new_handle['encoder'].setHubPort(int(new_handle['encoderPort']['value']))513 new_handle['encoder'].setIsHubPortDevice(False)514 new_handle['encoder'].setChannel(0)515 new_handle['encoder'].openWaitForAttachment(5000)516 new_handle['encoder'].setDataInterval(20)517 i = 0518 while i < 120:519 try:520 new_handle['encoder'].getPosition()521 except Exception:522 time.sleep(1)523 i += 1524 else:525 break526 # check if accelerometer is enabled527 if new_handle['accelerometerEnable']['value'] == 'true':528 new_handle['accelerometer'] = Accelerometer()529 new_handle['accelerometer'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))530 new_handle['accelerometer'].setHubPort(int(new_handle['spatialPort']['value']))531 new_handle['accelerometer'].setIsHubPortDevice(False)532 new_handle['accelerometer'].setChannel(0)533 new_handle['accelerometer'].openWaitForAttachment(5000)534 new_handle['accelerometer'].setDataInterval(20)535 i = 0536 while i < 120:537 try:538 new_handle['accelerometer'].getAcceleration()539 except Exception:540 time.sleep(1)541 i += 1542 else:543 break544 # check if gyroscope is enabled 545 if new_handle['gyroscopeEnable']['value'] == 'true':546 new_handle['gyroscope'] = Gyroscope()547 new_handle['gyroscope'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))548 new_handle['gyroscope'].setHubPort(int(new_handle['spatialPort']['value']))549 new_handle['gyroscope'].setIsHubPortDevice(False)550 new_handle['gyroscope'].setChannel(0)551 new_handle['gyroscope'].openWaitForAttachment(5000)552 new_handle['gyroscope'].setDataInterval(20)553 i = 0554 while i < 120:555 try:556 new_handle['gyroscope'].getAngularRate()557 except Exception:558 time.sleep(1)559 i += 1560 else:561 break562 # check if magnetometer enable is enabled 563 if new_handle['magnetometerEnable']['value'] == 'true':564 new_handle['magnetometer'] = Magnetometer()565 new_handle['magnetometer'].setDeviceSerialNumber(int(new_handle['hubSN']['value']))566 new_handle['magnetometer'].setHubPort(int(new_handle['spatialPort']['value']))567 new_handle['magnetometer'].setIsHubPortDevice(False)568 new_handle['magnetometer'].setChannel(0)569 new_handle['magnetometer'].openWaitForAttachment(5000)570 new_handle['magnetometer'].setDataInterval(20)571 i = 0572 while i < 120:573 try:574 new_handle['magnetometer'].getMagneticField()575 except Exception:576 time.sleep(1)577 i += 1578 else:579 break580 # check if hub has changed, if so init restart 581 if new_handle['hubSN']['value'] != handle['hubSN']['value']:582 new_handle['restart'] = 'yes'583 else:584 new_handle['restart'] = 'no'585 except Exception as ex:586 _LOGGER.exception("wind_turbine exception: {}".format(str(ex)))587 raise ex588 # counter to know when to run process589 new_handle['tempHumCount'] = 0590 new_handle['currentCount'] = 0591 new_handle['encoderCount'] = 0592 new_handle['accelerometerCount'] = 0593 new_handle['gyroscopeCount'] = 0594 new_handle['magnetometerCount'] = 0595 # counter of last encoder value596 new_handle['encoderPreviousValue'] = handle['encoderPreviousValue']597 return new_handle598def plugin_shutdown(handle):599 """ Shutdowns the plugin doing required cleanup, to be called prior to the South plugin service being shut down.600 Args:601 handle: handle returned by the plugin initialisation call602 Returns:603 plugin shutdown604 """605 try:606 handle['humidity'].close()607 handle['temperature'].close()608 handle['current'].close()609 handle['encoder'].close()610 handle['accelerometer'].close()611 handle['gyroscope'].close()612 handle['magnetometer'].close()613 except Exception as ex:614 _LOGGER.exception("wind_turbine exception: {}".format(str(ex)))615 raise ex...
manager.py
Source:manager.py
...76 }77 ObjectHandleTable = {78 }79 @staticmethod80 def new_handle():81 handle_id = ObjectManager.HANDLE_ID82 ObjectManager.HANDLE_ID += 483 return handle_id84 @staticmethod85 def new_id():86 _id = ObjectManager.OBJECT_ID87 ObjectManager.OBJECT_ID += 488 return _id89 @staticmethod90 def new_pid():91 pid = ObjectManager.PROCESS_ID92 ObjectManager.PROCESS_ID += 493 return pid94 @staticmethod95 def new_tid():96 tid = ObjectManager.THREAD_ID97 ObjectManager.THREAD_ID += 498 return tid99 @staticmethod100 def check_object_by_name(name):101 if name in ObjectManager.ObjectNameTable:102 handle = ObjectManager.new_handle()103 oid = ObjectManager.ObjectNameTable[name]104 ObjectManager.ObjectHandleTable[handle] = oid105 ObjectManager.ObjectTable[oid].inc_refcount()106 return handle107 return -1108 @staticmethod109 def get_object_handle(objstring, *args):110 if objstring == 'File':111 path = args[0]112 new_handle = ObjectManager.check_object_by_name(path)113 if new_handle != -1:114 return new_handle115 new_handle = ObjectManager.create_new_object(objstring, *args)116 if new_handle != INVALID_HANDLE_VALUE:117 ObjectManager.ObjectNameTable[path] = ObjectManager.ObjectHandleTable[new_handle]118 elif objstring == 'MMFile':119 name = args[5]120 new_handle = ObjectManager.check_object_by_name(name)121 if new_handle != -1:122 return new_handle123 124 new_handle = ObjectManager.create_new_object(objstring, *args)125 else:126 new_handle = ObjectManager.create_new_object(objstring, args)127 return new_handle128 @staticmethod129 def create_new_object(objstring, *args): 130 obj = ObjectManager.EmuObjectNames[objstring]131 new_obj = obj(*args)132 new_obj.set_oid(ObjectManager.new_id())133 if objstring == 'Process':134 uc_eng = args[0]135 new_obj.set_pid(ObjectManager.new_pid())136 new_obj.set_gdt(EmuGDT(uc_eng)) # actually, this is done by core ntoskrnl137 138 elif objstring == 'Thread':139 new_obj.set_tid(ObjectManager.new_tid())140 elif objstring == 'File':141 if not new_obj.obj:142 return INVALID_HANDLE_VALUE143 handle = ObjectManager.add_object(new_obj)144 return handle145 146 @staticmethod147 def add_object(obj):148 handle = ObjectManager.new_handle()149 ObjectManager.ObjectTable[obj.oid] = obj150 ObjectManager.ObjectHandleTable[handle] = obj.oid151 obj.inc_refcount()152 return handle153 @staticmethod154 def get_obj_by_handle(handle):155 if handle in ObjectManager.ObjectHandleTable:156 oid = ObjectManager.ObjectHandleTable[handle]157 return ObjectManager.ObjectTable[oid]158 else:159 return None160 161 @staticmethod162 def close_handle(handle_id):...
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!!