Best JavaScript code snippet using playwright-internal
data-logger-bg96-mqtt.js
Source:data-logger-bg96-mqtt.js
1/*2 Example how to send telemetry data to the Bosch IoT Suite using the Quectel BG96 modem and built-in MQTT client.3 Uses a simple Finite State Machine to introduce robustness against communication errors.4 Note: If you have chosen to upload the code to RAM (default) in the Espruino IDE, you need5 to interactively call "onInit();" on the device's JavaScript console after uploading.6 Debug output to console can be controlled via variable connection_options.debug7 Low memory is an issue!8 Use the "online minification" feature of the Espruino IDE if you run short on9 memory (e.g. "Closure (online))10 Although not completely reproduced: For standalone operation, please turn off debug output to console,11 (debug: false) as this might lead to the system freezing up.12 Copyright (C) 2019 Wolfgang Klenk <wolfgang.klenk@gmail.com>13 This program is free software: you can redistribute it and/or modify14 it under the terms of the GNU General Public License as published by15 the Free Software Foundation, either version 3 of the License, or16 (at your option) any later version.17 This program is distributed in the hope that it will be useful,18 but WITHOUT ANY WARRANTY; without even the implied warranty of19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the20 GNU General Public License for more details.21 You should have received a copy of the GNU General Public License22 along with this program. If not, see <https://www.gnu.org/licenses/>.23*/24var ENTERING_STATE = 'Entering State';25var ERROR_IN_STATE = 'Error in State';26var STATE_SETUP_EXTERNAL_HARDWARE = 'Setup External Hardware';27var STATE_CONFIGURE_MODEM = 'Configure Modem';28var STATE_REGISTER_TO_NETWORK = 'Register To Network';29var STATE_OPEN_MQTT_NETWORK = 'Open MQTT Network';30var STATE_CONNECT_TO_SERVER = 'Connect To Server';31var STATE_REQUEST_DESIRED_IL_CONFIG = 'Request desired indicator light config';32var STATE_PUBLISH_TELEMETRY_DATA = 'Publish Telemetry Data';33var STATE_SUBSCRIBE_TO_COMMANDS = "Subscribe To Commands";34var STATE_SLEEP = 'Sleep';35var STATE_RESET_MODEM = 'Reset Modem';36var STATE_POWER_DOWN = 'Power Down';37var at;38var bme280;39var errCnt = 0;40var updateCnt = 1;41var smRestartCnt = 0;42var qmtstat = 0;43var indicatorLightOn = false;44var indicatorLightReportedVersion = -1;45var indicatorLightDesiredVersion = 0;46var msgId = 1; // Increase msgId each time a message with QoS=1 is sent47var sm = require("StateMachine").FSM();48// NB1 connectivity settings for 1NCE49/*50var connection_options = {51 band: "B8",52 apn: "iot.1nce.net",53 operator: "26201",54 debug: false55};56*/57// NB1 connectivity settings for Vodafone Germany58var connection_options = {59 band: "B20",60 apn: "vgesace.nb.iot",61 operator: "26202",62 debug: true // Print communication with BG96 module to console.63};64// Use MQTT adapter of Bosch IoT Suite Hub65var mqtt_options = {66 server: 'mqtt.bosch-iot-hub.com',67 port: 8883,68 username: 'my.name.space_myDeviceId', // value returned from device provisioning69 hubTenantId: 'my-hub-tenant-id',70 password: 'my-device-secret'71};72var band_values = {73 "B1": "1",74 "B2": "2",75 "B3": "4",76 "B4": "8",77 "B5": "10",78 "B8": "80",79 "B12": "800",80 "B13": "1000",81 "B18": "20000",82 "B19": "40000",83 "B20": "80000",84 "B26": "2000000",85 "B28": "8000000"86};87sendAtCommand = function (command, timeoutMs, waitForLine) {88 return new Promise((resolve, reject) => {89 var answer = "";90 at.cmd(command + "\r\n", timeoutMs || 1E3, function processResponse(response) {91 if (undefined === response || "ERROR" === response || response.startsWith("+CME ERROR")) {92 reject(response ? (command + ": " + response) : (command + ": TIMEOUT"));93 } else if (waitForLine ? (response.startsWith(waitForLine)) : ("OK" === response)) {94 resolve(waitForLine ? response : answer);95 } else {96 answer += (answer ? "\n" : "") + response;97 return processResponse;98 }99 });100 });101};102sendAtCommandAndWaitForPrompt = function (command, timeoutMs, sendLineAfterPrompt, waitForLine) {103 return new Promise((resolve, reject) => {104 var prompt = '> ';105 var answer = "";106 if (sendLineAfterPrompt) {107 at.register(prompt, (line) => {108 at.unregister(prompt);109 at.write(sendLineAfterPrompt + '\x1A');110 return line.substr(2);111 });112 }113 at.cmd(command + "\r\n", timeoutMs, function processResponse(response) {114 if (undefined === response || "ERROR" === response || response.startsWith("+CME ERROR")) {115 // Unregister the prompt '> ' in case something went wrong.116 // If we don't, we get follow up errors when it is tried to again register the prompt.117 at.unregister(prompt);118 reject(response ? (command + ": " + response) : (command + ": TIMEOUT"));119 } else if (waitForLine ? (response.startsWith(waitForLine)) : ("OK" === response)) {120 resolve(waitForLine ? response : answer);121 } else {122 answer += (answer ? "\n" : "") + response;123 return processResponse;124 }125 });126 });127};128// Switch LED on/off129function controlLed(desiredIndicatorLightMode) {130 if (desiredIndicatorLightMode === 'off') {131 digitalWrite(LED1, false);132 indicatorLightOn = false;133 } else if (desiredIndicatorLightMode === 'on') {134 digitalWrite(LED1, true);135 indicatorLightOn = true;136 }137}138//139// Finite State Machine: States140//141// Setup external hardware.142function e_SetupExternalHardware() {143 if (connection_options.debug) console.log(ENTERING_STATE, STATE_SETUP_EXTERNAL_HARDWARE);144 return new Promise((resolve, reject) => {145 require("iTracker").setCellOn(true, (usart) => {146 resolve(usart);147 });148 })149 .then((usart) => {150 if (connection_options.debug) console.log("External modules connected.");151 at = require("AT").connect(usart);152 if (connection_options.debug) {153 at.debug(true);154 }155 return new Promise((resolve, reject) => {156 bme280 = require("iTracker").setEnvOn(true, () => {157 if (connection_options.debug) console.log("BME280 wiring set up.");158 resolve();159 });160 });161 })162 .then(() => {163 sm.signal('ok');164 })165 .catch((err) => {166 if (connection_options.debug) console.log(ERROR_IN_STATE, STATE_SETUP_EXTERNAL_HARDWARE, err);167 sm.signal('fail');168 });169}170// Configure BG96 module and MQTT software stack171function e_ConfigureModem() {172 if (connection_options.debug) console.log(ENTERING_STATE, STATE_CONFIGURE_MODEM);173 sendAtCommand('AT&F0')174 .then(() => sendAtCommand('ATE0'))175 .then(() => sendAtCommand('AT+CPIN?')) // Fails on locked PIN176 .then(() => {177 var band_value = band_values[connection_options.band];178 if (undefined === band_value) throw ("Unknown band: " + connection_options.band);179 return sendAtCommand('AT+QCFG="band",0,0,' + band_value + ',1');180 })181 .then(() => sendAtCommand('AT+QCFG="nwscanmode",3,1')) // Network Search Mode, LTE only182 .then(() => sendAtCommand('AT+QCFG="nwscanseq",030102,1')) // Network Search Sequence, NB-Iot, GSM, CatM1183 .then(() => sendAtCommand('AT+QCFG="iotopmode",1,1')) // LTE Search Mode: NB-IoT only184 .then(() => sendAtCommand('AT+QCFG="servicedomain",1,1')) // Set PS domain, PS only185 .then(() => sendAtCommand('AT+CGDCONT=1,"IP",' + JSON.stringify(connection_options.apn)))186 .then(() => sendAtCommand('AT+CFUN=1'))187 // Send keepalive message every 30 seconds188 .then(() => sendAtCommand('AT+QMTCFG="keepalive",0,30'))189 // SSL: Configure MQTT session into SSL mode190 .then(() => sendAtCommand('AT+QMTCFG="SSL",0,1,0'))191 .then(() => sendAtCommand('AT+QSSLCFG="sslversion",0,3')) // Require TLS 1.2192 // SSL: Configure trusted CA certificate193 // .then(() => sendAtCommand('AT+QSSLCFG="cacert",2,"cacert.pem"'))194 // SSL: Configure client certificate195 //.then(() => sendAtCommand('AT+QSSLCFG="clientcert",2,"cert.pem"'))196 // SSL: Configure private key197 //.then(() => sendAtCommand('AT+QSSLCFG="clientkey",2,"key.pem"'))198 // SSL: Authentication mode: Server and client authentication199 // .then(() => sendAtCommand('AT+QSSLCFG="seclevel",2,0')) // 0 = Neither server nor client authentication200 // SSL: Authentication version. Accept all SSL versions201 // .then(() => sendAtCommand('AT+QSSLCFG="sslversion",2,4')) // Support all SSL versions202 // SSL: Cipher suite: Support all cipher suites203 // .then(() => sendAtCommand('AT+QSSLCFG="ciphersuite",2,0xFFFF')) // Support all Ciphersuites204 // SSL: Ignore the time of authentication.205 .then(() => sendAtCommand('AT+QSSLCFG="ignorelocaltime",1'))206 .then(() => {207 sm.signal('ok');208 })209 .catch((err) => {210 if (connection_options.debug) console.log(ERROR_IN_STATE, STATE_CONFIGURE_MODEM, err);211 sm.signal('fail');212 });213}214// Register to network215function e_RegisterToNetwork() {216 if (connection_options.debug) console.log(ENTERING_STATE, STATE_REGISTER_TO_NETWORK);217 // Manually register to network.218 // Modem LED should flash on-off-off-off periodically to indicate network search219 sendAtCommand('AT+COPS=1,2,' + JSON.stringify(connection_options.operator) + ',9', 1800000)220 .then(() => {221 sm.signal('ok');222 })223 .catch((err) => {224 if (connection_options.debug) console.log('Error in state', STATE_REGISTER_TO_NETWORK, err);225 sm.signal('fail');226 });227}228// Open a network for MQTT client229function e_OpenMQTTNetwork() {230 if (connection_options.debug) console.log(ENTERING_STATE, STATE_OPEN_MQTT_NETWORK);231 sendAtCommand(232 'AT+QMTOPEN=0,' + JSON.stringify(mqtt_options.server) + ',' + mqtt_options.port,233 30000,234 '+QMTOPEN:')235 .then((line) => {236 if (connection_options.debug) console.log("+QMTOPEN line:", line);237 var qmtstat = '+QMTSTAT: ';238 at.unregisterLine(qmtstat);239 at.registerLine(qmtstat, (line) => {240 line = line.split(",");241 qmtstat = parseInt(line[1]);242 if (connection_options.debug) console.log("+QMTSTAT Error Code:", qmtstat);243 });244 sm.signal('ok');245 })246 .catch((err) => {247 if (connection_options.debug) console.log(ERROR_IN_STATE, STATE_OPEN_MQTT_NETWORK, err);248 sm.signal('fail');249 });250}251// Connect this client to MQTT server252function e_ConnectToServer() {253 if (connection_options.debug) console.log(ENTERING_STATE, STATE_CONNECT_TO_SERVER);254 sendAtCommand('AT+QMTCONN=0,' +255 JSON.stringify('some-client-id') +256 ',' +257 JSON.stringify(mqtt_options.username +258 '@' +259 mqtt_options.hubTenantId) +260 ',' +261 JSON.stringify(mqtt_options.password),262 15000,263 '+QMTCONN:')264 .then((line) => {265 if (connection_options.debug) console.log("+QMTCONN line:", line);266 sm.signal('ok');267 })268 .catch((err) => {269 if (connection_options.debug) console.log(ERROR_IN_STATE, STATE_CONNECT_TO_SERVER, err);270 sm.signal('fail');271 });272}273// Subscribe to the command channel of the Hub.274function e_SubscribeToCommands() {275 if (connection_options.debug) console.log(ENTERING_STATE, STATE_SUBSCRIBE_TO_COMMANDS);276 // Handler for incoming commands from the Hub277 var qmtrecv = '+QMTRECV: ';278 at.unregisterLine(qmtrecv);279 at.registerLine(qmtrecv, (line) => {280 // This callback is called whenever a line starting with "+QMTRECV:" is detected. A "line" means281 // a number of characters until a "\r" character is received. But this means, this WON'T WORK if the282 // payload itself contains a "\r" character. Keep that in mind.283 var openingBrace = line.indexOf('{');284 var payloadJson = JSON.parse(line.substr(openingBrace));285 if (connection_options.debug) console.log('Incoming Ditto message:', payloadJson);286 if (payloadJson.path === '/features/indicatorLight@desired/properties') {287 indicatorLightDesiredVersion = payloadJson.value.config.version;288 controlLed(payloadJson.value.config.mode);289 } else if (payloadJson.path === '/features/indicatorLight@desired/properties/config') {290 indicatorLightDesiredVersion = payloadJson.value.version;291 controlLed(payloadJson.value.mode);292 }293 });294 // Subscribe to incoming command messages from the Hub295 sendAtCommand('AT+QMTSUB=0,1,' +296 JSON.stringify("command/+/+/req/#") +297 ',1',298 15000,299 '+QMTSUB:')300 .then((line) => {301 if (connection_options.debug) console.log("+QMTSUB line:", line);302 // Wait 5 seconds in order to let the backend establish the connection to the device.303 return new Promise((resolve, reject) => {304 setTimeout(() => {305 resolve();306 }, 5000);307 });308 })309 .then((line) => {310 sm.signal('ok');311 })312 .catch((err) => {313 if (connection_options.debug) console.log(ERROR_IN_STATE, STATE_SUBSCRIBE_TO_COMMANDS, err);314 sm.signal('fail');315 });316}317// Publish telemetry data via MQTT318function e_PublishTelemetryData() {319 if (connection_options.debug) console.log(ENTERING_STATE, STATE_PUBLISH_TELEMETRY_DATA);320 var currentEnvironmentData = bme280.getData();321 var indicatorLightModeString = '"off"';322 if (indicatorLightOn === true) {323 indicatorLightModeString = '"on"';324 }325 // TODO: This actually only needs to be sent if desiredVersion != reportedVersion326 // Eclipse Ditto modify command for feature "indicatorLight"327 sendAtCommandAndWaitForPrompt('AT+QMTPUB=0,' + (msgId++) + ',1,0,' + // QoS = 1328 JSON.stringify("event"),329 5000,330 '{' +331 ' "topic": "org.klenk.connectivity.iot/rak8212/things/twin/commands/modify",' +332 ' "headers": {},' +333 ' "path": "/features/indicatorLight/properties",' +334 ' "value": {' +335 ' "config": {' +336 ' "version": ' + indicatorLightDesiredVersion + ',' +337 ' "mode": ' + indicatorLightModeString +338 ' }' +339 ' }' +340 '}',341 '+QMTPUB:'342 )343 .then((line) => {344 indicatorLightReportedVersion = indicatorLightDesiredVersion;345 // Eclipse Ditto modify command for feature "temperature"346 return sendAtCommandAndWaitForPrompt('AT+QMTPUB=0,0,0,0,' + // QoS = 0347 JSON.stringify("telemetry"),348 5000,349 '{' +350 ' "topic": "org.klenk.connectivity.iot/rak8212/things/twin/commands/modify",' +351 ' "headers": {},' +352 ' "path": "/features/temperature/properties",' +353 ' "value": {' +354 ' "status": {' +355 ' "value": ' + currentEnvironmentData.temp.toFixed(2) + ',' +356 ' "unit": "Degree Celsius"' +357 ' }' +358 ' }' +359 '}',360 '+QMTPUB:'361 );362 })363 .then((line) => {364 if (connection_options.debug) console.log("+QMTPUB line:", line);365 // Eclipse Ditto modify command for feature "humidity"366 return sendAtCommandAndWaitForPrompt('AT+QMTPUB=0,0,0,0,' + // QoS = 0367 JSON.stringify("telemetry"),368 5000,369 '{' +370 ' "topic": "org.klenk.connectivity.iot/rak8212/things/twin/commands/modify",' +371 ' "headers": {},' +372 ' "path": "/features/humidity/properties",' +373 ' "value": {' +374 ' "status": {' +375 ' "currentMeasured": ' + currentEnvironmentData.humidity.toFixed(2) +376 ' }' +377 ' }' +378 '}',379 '+QMTPUB:'380 );381 })382 .then((line) => {383 if (connection_options.debug) console.log("+QMTPUB line:", line);384 // Eclipse Ditto modify command for feature "barometricPressure"385 return sendAtCommandAndWaitForPrompt('AT+QMTPUB=0,0,0,0,' + // QoS = 0386 JSON.stringify("telemetry"),387 5000,388 '{' +389 ' "topic": "org.klenk.connectivity.iot/rak8212/things/twin/commands/modify",' +390 ' "headers": {},' +391 ' "path": "/features/barometricPressure/properties",' +392 ' "value": {' +393 ' "status": {' +394 ' "currentMeasured": ' + currentEnvironmentData.pressure.toFixed(2) +395 ' }' +396 ' }' +397 '}',398 '+QMTPUB:'399 );400 })401 .then((line) => {402 if (connection_options.debug) console.log("+QMTPUB line:", line);403 // Query the current bytes sent and received404 return sendAtCommand('AT+QGDCNT?', 1000, '+QGDCNT:');405 })406 .then((line) => {407 if (connection_options.debug) console.log("+QGDCNT line:", line);408 // Example: "+QGDCNT: 3708,5910"409 line = (line.split(':'))[1].split(',');410 // Eclipse Ditto modify command for feature "networkTraffic"411 return sendAtCommandAndWaitForPrompt('AT+QMTPUB=0,0,0,0,' + // QoS = 0412 JSON.stringify("telemetry"),413 5000,414 '{' +415 ' "topic": "org.klenk.connectivity.iot/rak8212/things/twin/commands/modify",' +416 ' "headers": {},' +417 ' "path": "/features/networkTraffic/properties",' +418 ' "value": {' +419 ' "totalBytesSent": ' + parseInt(line[0]) + ',' +420 ' "totalBytesReceived": ' + parseInt(line[1]) +421 ' }' +422 '}',423 '+QMTPUB:'424 );425 })426 .then((line) => {427 if (connection_options.debug) console.log("+QMTPUB line:", line);428 sm.signal('ok');429 })430 .catch((err) => {431 if (connection_options.debug) console.log(ERROR_IN_STATE, STATE_PUBLISH_TELEMETRY_DATA, err);432 sm.signal('fail');433 });434}435// Request feature "indicatorLight@desired" from Digital Twin436function e_RequestDesiredIndicatorLightConfig() {437 if (connection_options.debug) console.log(ENTERING_STATE, STATE_REQUEST_DESIRED_IL_CONFIG);438 return sendAtCommandAndWaitForPrompt('AT+QMTPUB=0,' + (msgId++) + ',1,0,' + // QoS = 1439 JSON.stringify("event"),440 5000,441 '{' +442 ' "topic": "org.klenk.connectivity.iot/rak8212/things/twin/commands/retrieve",' +443 ' "headers": {},' +444 ' "path": "/features/indicatorLight@desired/properties",' +445 ' "value": {}' +446 '}',447 '+QMTPUB:'448 )449 .then((line) => {450 if (connection_options.debug) console.log("+QMTPUB line:", line);451 // Wait 5 seconds in order to let the backend process the request before continuing452 return new Promise((resolve, reject) => {453 setTimeout(() => {454 resolve();455 }, 5000);456 });457 })458 .then((line) => {459 sm.signal('ok');460 })461 .catch((err) => {462 if (connection_options.debug) console.log(ERROR_IN_STATE, STATE_REQUEST_DESIRED_IL_CONFIG, err);463 sm.signal('fail');464 });465}466function e_Sleep(result) {467 if (connection_options.debug) console.log(ENTERING_STATE, STATE_SLEEP);468 return new Promise((resolve, reject) => {469 setTimeout(() => {470 resolve();471 }, 300000);472 })473 .then(() => {474 sm.signal('ok');475 });476}477function e_ResetModem(result) {478 if (connection_options.debug) console.log(ENTERING_STATE, STATE_RESET_MODEM);479 sendAtCommand('AT+QPOWD', 10000, 'POWERED DOWN')480 .then(() => {481 return new Promise((resolve, reject) => {482 setTimeout(() => {483 resolve();484 }, 10000);485 });486 })487 .then(() => {488 if (connection_options.debug) console.log('Powered down');489 sm.signal('ok');490 })491 .catch((err) => {492 if (connection_options.debug) console.log(ERROR_IN_STATE, STATE_RESET_MODEM, err);493 sm.signal('ok');494 });495}496//497// Finite State Machine: Transitions498//499function t_SetupExternalHardware(result) {500 return { state: STATE_CONFIGURE_MODEM };501}502function t_ConfigureModem(result) {503 return { state: STATE_REGISTER_TO_NETWORK };504}505function t_RegisterToNetwork(result) {506 switch (result) {507 case ('ok'):508 return { state: STATE_OPEN_MQTT_NETWORK };509 default:510 return { state: STATE_RESET_MODEM };511 }512}513function t_OpenMQTTNetwork(result) {514 if (qmtstat > 0) {515 return { state: STATE_RESET_MODEM };516 }517 switch (result) {518 case ('ok'):519 return { state: STATE_CONNECT_TO_SERVER };520 default:521 return { state: STATE_RESET_MODEM };522 }523}524function t_ConnectToServer(result) {525 if (qmtstat > 0) {526 return { state: STATE_RESET_MODEM };527 }528 switch (result) {529 case ('ok'):530 return { state: STATE_SUBSCRIBE_TO_COMMANDS };531 default:532 return { state: STATE_RESET_MODEM };533 }534}535function t_SubscribeToCommands(result) {536 if (qmtstat > 0) {537 return { state: STATE_RESET_MODEM };538 }539 switch (result) {540 case ('ok'):541 return { state: STATE_REQUEST_DESIRED_IL_CONFIG };542 default:543 return { state: STATE_RESET_MODEM };544 }545}546function t_PublishTelemetryData(result) {547 if (qmtstat > 0) {548 return { state: STATE_RESET_MODEM };549 }550 switch (result) {551 case ('ok'):552 errCnt = 0; // Reset error counter553 updateCnt++;554 return { state: STATE_SLEEP };555 default:556 errCnt++;557 if (errCnt >= 3) {558 errCnt = 0;559 return { state: STATE_RESET_MODEM };560 }561 else {562 return { state: STATE_SLEEP };563 }564 }565}566function t_RequestDesiredIndicatorLightConfig(result) {567 if (qmtstat > 0) {568 return { state: STATE_RESET_MODEM };569 }570 switch (result) {571 case ('ok'):572 return { state: STATE_PUBLISH_TELEMETRY_DATA };573 default:574 return { state: STATE_RESET_MODEM };575 }576}577function t_Sleep(result) {578 if (qmtstat > 0) {579 return { state: STATE_RESET_MODEM };580 }581 return { state: STATE_PUBLISH_TELEMETRY_DATA };582}583function t_ResetModem(result) {584 return { state: STATE_POWER_DOWN };585}586function onInit() {587 Bluetooth.setConsole(true); // Don't want to have console on "Serial1" that is used for modem.588 sm.define({ name: STATE_SETUP_EXTERNAL_HARDWARE, enter: e_SetupExternalHardware, signal: t_SetupExternalHardware });589 sm.define({ name: STATE_CONFIGURE_MODEM, enter: e_ConfigureModem, signal: t_ConfigureModem });590 sm.define({ name: STATE_REGISTER_TO_NETWORK, enter: e_RegisterToNetwork, signal: t_RegisterToNetwork });591 sm.define({ name: STATE_OPEN_MQTT_NETWORK, enter: e_OpenMQTTNetwork, signal: t_OpenMQTTNetwork });592 sm.define({ name: STATE_CONNECT_TO_SERVER, enter: e_ConnectToServer, signal: t_ConnectToServer });593 sm.define({ name: STATE_REQUEST_DESIRED_IL_CONFIG, enter: e_RequestDesiredIndicatorLightConfig, signal: t_RequestDesiredIndicatorLightConfig });594 sm.define({ name: STATE_SUBSCRIBE_TO_COMMANDS, enter: e_SubscribeToCommands, signal: t_SubscribeToCommands });595 sm.define({ name: STATE_PUBLISH_TELEMETRY_DATA, enter: e_PublishTelemetryData, signal: t_PublishTelemetryData });596 sm.define({ name: STATE_SLEEP, enter: e_Sleep, signal: t_Sleep });597 sm.define({ name: STATE_RESET_MODEM, enter: e_ResetModem, signal: t_ResetModem });598 sm.define({ name: STATE_POWER_DOWN });599 sm.init(STATE_SETUP_EXTERNAL_HARDWARE);600 // If the state machine is in state "Power Down", then restart the state machine.601 setInterval(() => {602 if (connection_options.debug) console.log("Checking state machine state");603 if (sm.state === STATE_POWER_DOWN) {604 if (connection_options.debug) console.log('Restarting State Machine');605 smRestartCnt++;606 sm.init(STATE_SETUP_EXTERNAL_HARDWARE);607 }608 }, 600000);...
data-logger-device-setup.js
Source:data-logger-device-setup.js
...214 'AT+QHTTPGET=60,' + headers.length,215 60000,216 headers);217 })218 .then(() => waitForLine('+QHTTPGET'))219 .then((line) => {220 console.log('+QHTTPGET response line:', line);221 // Returns something like "+QHTTPGET: 0,404,0"222 var responseValues = line.substr(10).split(',');223 var errorCode = parseInt(responseValues[0], 10);224 var httpResponseCode = parseInt(responseValues[1], 10);225 var contentLength = parseInt(responseValues[2], 10);226 console.log('Error code:', errorCode, 'HTTP response code:', httpResponseCode, 'Content length:', contentLength);227 if (contentLength > 0) {228 return sendAtCommand('AT+QHTTPREAD=80');229 } else {230 return httpResponseCode;231 }232 });233}234// HTTP POST Request on /registration/{tenant-id}235function postDeviceRegistration() {236 // Set URL of resource to request.237 var urlRegistration = binding_credentials["device-registry"]["registration-endpoint"];238 console.log('Registration URL:', urlRegistration);239 return sendAtCommandAndWaitForConnect('AT+QHTTPURL=' + urlRegistration.length, 10000, urlRegistration)240 // Send HTTP POST request.241 .then(() => {242 var body = '{ "device-id": "' + deviceId + '", "enabled": true }';243 var urlParts = url.parse(urlRegistration);244 var headers = 'POST ' + urlParts.path + ' HTTP/1.1'245 + '\r\n'246 + 'Host: ' + urlParts.host247 + '\r\n'248 + 'Authorization: Basic '249 + btoa(binding_credentials["device-registry"]["username"] + ":" + binding_credentials["device-registry"]["password"])250 + '\r\n'251 + 'Accept: application/json'252 + '\r\n'253 + 'Content-Type: application/json'254 + '\r\n'255 + 'Content-Length: ' + body.length256 + '\r\n'257 + 'User-Agent: Quectel BG96 module on RAK8212'258 + '\r\n'259 + '\r\n'; // Additional empty line to mark end of headers260 console.log('now sending post request', headers);261 return sendAtCommandAndWaitForConnect(262 'AT+QHTTPPOST=' + (headers.length + body.length),263 60000,264 headers + body);265 })266 .then(() => waitForLine('+QHTTPPOST'))267 .then((line) => {268 console.log('+QHTTPPOST response line:', line);269 // Returns something like "+QHTTPPOST: 0,201,0"270 var responseValues = line.substr(11).split(',');271 var errorCode = parseInt(responseValues[0], 10);272 var httpResponseCode = parseInt(responseValues[1], 10);273 var contentLength = parseInt(responseValues[2], 10);274 console.log('Error code:', errorCode, 'HTTP response code:', httpResponseCode, 'Content length:', contentLength);275 if (contentLength > 0) {276 return sendAtCommand('AT+QHTTPREAD=80');277 } else {278 return httpResponseCode;279 }280 });281}282// HTTP DELETE Request on /registration/{tenant-id}/{device-id}283function deleteDeviceRegistration() {284 // Set URL of resource to request.285 var urlRegistration = binding_credentials["device-registry"]["registration-endpoint"] + '/' + deviceId;286 console.log('Registration URL:', urlRegistration);287 return sendAtCommandAndWaitForConnect('AT+QHTTPURL=' + urlRegistration.length, 10000, urlRegistration)288 // Send HTTP DELETE request.289 .then(() => {290 var urlParts = url.parse(urlRegistration);291 var headers = 'DELETE ' + urlParts.path + ' HTTP/1.1'292 + '\r\n'293 + 'Host: ' + urlParts.host294 + '\r\n'295 + 'Authorization: Basic '296 + btoa(binding_credentials["device-registry"]["username"] + ":" + binding_credentials["device-registry"]["password"])297 + '\r\n'298 + 'Accept: application/json'299 + '\r\n'300 + 'User-Agent: Quectel BG96 module on RAK8212'301 + '\r\n'302 + '\r\n'; // Additional empty line to mark end of headers303 return sendAtCommandAndWaitForConnect(304 'AT+QHTTPGET=60,' + headers.length,305 60000,306 headers);307 })308 .then(() => waitForLine('+QHTTPGET'))309 .then((line) => {310 console.log('+QHTTPGET response line:', line);311 // Returns something like "+QHTTPGET: 0,404,0"312 var responseValues = line.substr(10).split(',');313 var errorCode = parseInt(responseValues[0], 10);314 var httpResponseCode = parseInt(responseValues[1], 10);315 var contentLength = parseInt(responseValues[2], 10);316 console.log('Error code:', errorCode, 'HTTP response code:', httpResponseCode, 'Content length:', contentLength);317 if (contentLength > 0) {318 return sendAtCommand('AT+QHTTPREAD=80');319 } else {320 return httpResponseCode;321 }322 });323}324// HTTP GET Request on /credentials/{tenant-id}325// Let auth-id be the same as device-id326function getDeviceCredentials() {327 // Set URL of resource to request.328 var urlCredentials = binding_credentials["device-registry"]["credentials-endpoint"]329 + '?auth-id=' + deviceId + '&type=hashed-password';330 console.log('Credentials URL:', urlCredentials);331 return sendAtCommandAndWaitForConnect('AT+QHTTPURL=' + urlCredentials.length, 10000, urlCredentials)332 // Send HTTP GET request.333 .then(() => {334 var urlParts = url.parse(urlCredentials);335 var headers = 'GET ' + urlParts.path + ' HTTP/1.1'336 + '\r\n'337 + 'Host: ' + urlParts.host338 + '\r\n'339 + 'Authorization: Basic '340 + btoa(binding_credentials["device-registry"]["username"] + ":" + binding_credentials["device-registry"]["password"])341 + '\r\n'342 + 'Accept: application/json'343 + '\r\n'344 + 'User-Agent: Quectel BG96 module on RAK8212'345 + '\r\n'346 + '\r\n'; // Additional empty line to mark end of headers347 return sendAtCommandAndWaitForConnect(348 'AT+QHTTPGET=60,' + headers.length,349 60000,350 headers);351 })352 .then(() => waitForLine('+QHTTPGET'))353 .then((line) => {354 console.log('+QHTTPGET response line:', line);355 // Returns something like "+QHTTPGET: 0,404,0"356 var responseValues = line.substr(10).split(',');357 var errorCode = parseInt(responseValues[0], 10);358 var httpResponseCode = parseInt(responseValues[1], 10);359 var contentLength = parseInt(responseValues[2], 10);360 console.log('Error code:', errorCode, 'HTTP response code:', httpResponseCode, 'Content length:', contentLength);361 if (contentLength > 0) {362 return sendAtCommand('AT+QHTTPREAD=80');363 } else {364 return httpResponseCode;365 }366 });367}368// HTTP POST Request on /credentials/{tenant-id}369// Let auth-id be the same as device-id370function postDeviceCredentials() {371 // Set URL of resource to request.372 var urlCredentials = binding_credentials["device-registry"]["credentials-endpoint"];373 console.log('Registration URL:', urlCredentials);374 return sendAtCommandAndWaitForConnect('AT+QHTTPURL=' + urlCredentials.length, 10000, urlCredentials)375 // Send HTTP POST request.376 .then(() => {377 var body = '{'378 + '"device-id": "' + deviceId + '",'379 + '"type": "hashed-password",'380 + '"auth-id": "' + deviceId + '",'381 + '"enabled": true,'382 + '"secrets": ['383 + '{'384 + ' "password": "secret"' // Password is "secret"385 + '}'386 + ']'387 + '}';388 var urlParts = url.parse(urlCredentials);389 var headers = 'POST ' + urlParts.path + ' HTTP/1.1'390 + '\r\n'391 + 'Host: ' + urlParts.host392 + '\r\n'393 + 'Authorization: Basic '394 + btoa(binding_credentials["device-registry"]["username"] + ":" + binding_credentials["device-registry"]["password"])395 + '\r\n'396 + 'Accept: application/json'397 + '\r\n'398 + 'Content-Type: application/json'399 + '\r\n'400 + 'Content-Length: ' + body.length401 + '\r\n'402 + 'User-Agent: Quectel BG96 module on RAK8212'403 + '\r\n'404 + '\r\n'; // Additional empty line to mark end of headers405 console.log('now sending post request', headers);406 return sendAtCommandAndWaitForConnect(407 'AT+QHTTPPOST=' + (headers.length + body.length),408 60000,409 headers + body);410 })411 .then(() => waitForLine('+QHTTPPOST'))412 .then((line) => {413 console.log('+QHTTPPOST response line:', line);414 // Returns something like "+QHTTPPOST: 0,201,0"415 var responseValues = line.substr(11).split(',');416 var errorCode = parseInt(responseValues[0], 10);417 var httpResponseCode = parseInt(responseValues[1], 10);418 var contentLength = parseInt(responseValues[2], 10);419 console.log('Error code:', errorCode, 'HTTP response code:', httpResponseCode, 'Content length:', contentLength);420 if (contentLength > 0) {421 return sendAtCommand('AT+QHTTPREAD=80');422 } else {423 return httpResponseCode;424 }425 });426}427// HTTP DELETE Request on /credentials/{tenant-id}428// Let auth-id be the same as device-id429function deleteDeviceCredentials() {430 // Set URL of resource to request.431 var urlCredentials = binding_credentials["device-registry"]["credentials-endpoint"]432 + '?auth-id=' + deviceId + '&type=hashed-password';433 console.log('Credentials URL:', urlCredentials);434 return sendAtCommandAndWaitForConnect('AT+QHTTPURL=' + urlCredentials.length, 10000, urlCredentials)435 // Send HTTP DELETE request.436 .then(() => {437 var urlParts = url.parse(urlCredentials);438 var headers = 'DELETE ' + urlParts.path + ' HTTP/1.1'439 + '\r\n'440 + 'Host: ' + urlParts.host441 + '\r\n'442 + 'Authorization: Basic '443 + btoa(binding_credentials["device-registry"]["username"] + ":" + binding_credentials["device-registry"]["password"])444 + '\r\n'445 + 'Accept: application/json'446 + '\r\n'447 + 'User-Agent: Quectel BG96 module on RAK8212'448 + '\r\n'449 + '\r\n'; // Additional empty line to mark end of headers450 return sendAtCommandAndWaitForConnect(451 'AT+QHTTPGET=60,' + headers.length,452 60000,453 headers);454 })455 .then(() => waitForLine('+QHTTPGET'))456 .then((line) => {457 console.log('+QHTTPGET response line:', line);458 // Returns something like "+QHTTPGET: 0,404,0"459 var responseValues = line.substr(10).split(',');460 var errorCode = parseInt(responseValues[0], 10);461 var httpResponseCode = parseInt(responseValues[1], 10);462 var contentLength = parseInt(responseValues[2], 10);463 console.log('Error code:', errorCode, 'HTTP response code:', httpResponseCode, 'Content length:', contentLength);464 if (contentLength > 0) {465 return sendAtCommand('AT+QHTTPREAD=80');466 } else {467 return httpResponseCode;468 }469 });...
electron.js
Source:electron.js
...167 handleSIGHUP: true,168 onExit: () => {}169 });170 const waitForXserverError = new Promise(async (resolve, reject) => {171 waitForLine(progress, launchedProcess, /Unable to open X display/).then(() => reject(new Error(['Unable to open X display!', `================================`, 'Most likely this is because there is no X server available.', "Use 'xvfb-run' on Linux to launch your tests with an emulated display server.", "For example: 'xvfb-run npm run test:e2e'", `================================`, progress.metadata.log].join('\n')))).catch(() => {});172 });173 const nodeMatch = await waitForLine(progress, launchedProcess, /^Debugger listening on (ws:\/\/.*)$/);174 const nodeTransport = await _transport.WebSocketTransport.connect(progress, nodeMatch[1]);175 const nodeConnection = new _crConnection.CRConnection(nodeTransport, _helper.helper.debugProtocolLogger(), browserLogsCollector); // Immediately release exiting process under debug.176 waitForLine(progress, launchedProcess, /Waiting for the debugger to disconnect\.\.\./).then(() => {177 nodeTransport.close();178 }).catch(() => {});179 const chromeMatch = await Promise.race([waitForLine(progress, launchedProcess, /^DevTools listening on (ws:\/\/.*)$/), waitForXserverError]);180 const chromeTransport = await _transport.WebSocketTransport.connect(progress, chromeMatch[1]);181 const browserProcess = {182 onclose: undefined,183 process: launchedProcess,184 close: gracefullyClose,185 kill186 };187 const contextOptions = { ...options,188 noDefaultViewport: true189 };190 const browserOptions = { ...this._playwrightOptions,191 name: 'electron',192 isChromium: true,193 headful: true,194 persistent: contextOptions,195 browserProcess,196 protocolLogger: _helper.helper.debugProtocolLogger(),197 browserLogsCollector,198 artifactsDir,199 downloadsPath: artifactsDir,200 tracesDir: artifactsDir201 };202 (0, _browserContext.validateBrowserContextOptions)(contextOptions, browserOptions);203 const browser = await _crBrowser.CRBrowser.connect(chromeTransport, browserOptions);204 app = new ElectronApplication(this, browser, nodeConnection, launchedProcess);205 return app;206 }, _timeoutSettings.TimeoutSettings.timeout(options));207 }208}209exports.Electron = Electron;210function waitForLine(progress, process, regex) {211 return new Promise((resolve, reject) => {212 const rl = readline.createInterface({213 input: process.stderr214 });215 const failError = new Error('Process failed to launch!');216 const listeners = [_eventsHelper.eventsHelper.addEventListener(rl, 'line', onLine), _eventsHelper.eventsHelper.addEventListener(rl, 'close', reject.bind(null, failError)), _eventsHelper.eventsHelper.addEventListener(process, 'exit', reject.bind(null, failError)), // It is Ok to remove error handler because we did not create process and there is another listener.217 _eventsHelper.eventsHelper.addEventListener(process, 'error', reject.bind(null, failError))];218 progress.cleanupWhenAborted(cleanup);219 function onLine(line) {220 const match = line.match(regex);221 if (!match) return;222 cleanup();223 resolve(match);224 }...
upload-ssl-certs-to-bg96.js
Source:upload-ssl-certs-to-bg96.js
1/*2 Example how to upload SSL certificates to the Quectel BG96 module using AT commands.3 Steps:4 Cut and paste your certificates in PEM format to the code.5 Interactively call "uploadCertificates();" on the device's JavaScript console after6 uploading the code to the device.7 Copyright (C) 2019 Wolfgang Klenk <wolfgang.klenk@gmail.com>8 This program is free software: you can redistribute it and/or modify9 it under the terms of the GNU General Public License as published by10 the Free Software Foundation, either version 3 of the License, or11 (at your option) any later version.12 This program is distributed in the hope that it will be useful,13 but WITHOUT ANY WARRANTY; without even the implied warranty of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 You should have received a copy of the GNU General Public License17 along with this program. If not, see <https://www.gnu.org/licenses/>.18*/19var debug = false;20var FILENAME_CLIENT_CERT = "cert.pem";21var FILENAME_PRIVATE_KEY = "key.pem";22var FILENAME_TRUSTED_ROOT_CA = "cacert.pem";23var at;24// 3a34634a38-certificate.pem.crt - Cut and paste25var client_cert = '-----BEGIN CERTIFICATE-----\n' +26 'MIIDWjCCAkKgAwIBAgIVAJZ543Y5NgA10ni3ARw3huZhA01OMA0GCSqGSIb3DQEB\n' +27 'CwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\n' +28 'IEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0xOTAzMjUyMDMw\n' +29 'NDZaFw00OTEyMzEyMzU5NTlaMB4xHDAaBgNVBAMME0FXUyBJb1QgQ2VydGlmaWNh\n' +30 'dGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCrFmv9kMjJ0Jhucd3\n' +31 'hThnHwjI1vvYWfHqho4yZhy5kFlot0e0GwtdInMYdiKISlTDQz90iK2dnp6U1aW3\n' +32 'IajR93MFI7Vj9hyOr/cci98zqnOxnvcXf4Lxi6zrcw/aMSB3WIFRWPnzpERIeZJO\n' +33 '+PK7YAnJ0ynZo4ir3c8IuDX8u8pj6PB4ohrkHz0O4i8qN7WNFgRgmR8oAf4D6nzC\n' +34 'gLmemN/xaEB54C2lnSTIpFmyp7qHQBg2lULqDOQkig6bV8K1qrfsLXLECTa+rhoF\n' +35 'VqFrqXqJw9djyj93LAkTjMdXQu8mWVKnvYi0TLXpf1m4H+UMbgQNgsMRg/CoHPmy\n' +36 'lq4tAgMBAAGjYDBeMB8GA1UdIwQYMBaAFPYoAgVcRLr4N6NKDWJpQ6NWJKKHMB0G\n' +37 'A1UdDgQWBBTVKpy0Jrf8M6UVSyAV5qPEtDVrsTAMBgNVHRMBAf8EAjAAMA4GA1Ud\n' +38 'DwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAYvr983hMVoUgd3WXQsW74AI0\n' +39 '4ycas0hPAUSLW6i5J4RkLY9rOH+ppnycmKCD3oOfVCpBlWf5nhsJ12p7NCgYJSa8\n' +40 'Cl3GjWdXpoYX+Sv7BiMBHFfzNQjZf6A/vk+9bCg1hTfWY2+wWsvqQ/u/xWG9rgaF\n' +41 'rtvdZ3dYbrXVKjq5QvKqxuLmM0Wbsf7gmo9WxF7wDF5uZHGKNH++qn9Id7txGbyO\n' +42 'nTlJ4447tguozlbTMl9Bup9+iUMeXOZwhzHI45uqnA4AYVUDB2fu+TBz1ogwnXOD\n' +43 'ZlkWZNh/iBObuNC4J8/njsXP7R0eCNj9K4FFoInQ776COPe9hSQhnMequlw2MQ==\n' +44 '-----END CERTIFICATE-----\n';45// 3a34634a38-private.pem.key - Cut and paste46var client_private_key = '-----BEGIN RSA PRIVATE KEY-----\n' +47 'MIIEpAIBAAKCAQEAwqxZr/ZDIydCYbnHd4U4Zx8IyNb72Fnx6oaOMmYcuZBZaLdH\n' +48 'tBsLXSJzGHYiiEpUw0M/dIitnZ6elNWltyGo0fdzBSO1Y/Ycjq/3HIvfM6pzsZ73\n' +49 '72mTAlFiF2lPDId+kkFDiuSp6lkz30f5/Nl+LZwUGtPaANykjocIdOWGoi+Z2lNe\n' +50 'q6QT+CyUCX7I40wIkPfujsYoBGvM/MDRqnN36J4Kjc/RdnXPs25tLw==\n' +51 '-----END RSA PRIVATE KEY-----\n';52// RSA 2048 bit key: Amazon Root CA 153var trusted_root_ca = '-----BEGIN CERTIFICATE-----\n' +54 'MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n' +55 'ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n' +56 'b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n' +57 'MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n' +58 'b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n' +59 'ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n' +60 '9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n' +61 'IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n' +62 'VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n' +63 '93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n' +64 'jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n' +65 'AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n' +66 'A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n' +67 'U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n' +68 'N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n' +69 'o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n' +70 '5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n' +71 'rqXRfboQnoZsG4q5WTP468SQvvG5\n' +72 '-----END CERTIFICATE-----';73sendAtCommand = function (command, timeoutMs, waitForLine) {74 return new Promise((resolve, reject) => {75 var answer = "";76 at.cmd(command + "\r\n", timeoutMs || 1E3, function processResponse(response) {77 if (undefined === response || "ERROR" === response || response.startsWith("+CME ERROR")) {78 reject(response ? (command + ": " + response) : (command + ": TIMEOUT"));79 } else if (waitForLine ? (response.startsWith(waitForLine)) : ("OK" === response)) {80 resolve(waitForLine ? response : answer);81 } else {82 answer += (answer ? "\n" : "") + response;83 return processResponse;84 }85 });86 });87};88sendAtCommandAndWaitForPrompt = function (command, timeoutMs, sendLineAfterPrompt, waitForLine) {89 return new Promise((resolve, reject) => {90 var prompt = 'CONNECT';91 var answer = "";92 if (sendLineAfterPrompt) {93 at.register(prompt, (line) => {94 at.unregister(prompt);95 at.write(sendLineAfterPrompt);96 return line.substr(prompt.length);97 });98 }99 at.cmd(command + "\r\n", timeoutMs, function processResponse(response) {100 if (undefined === response || "ERROR" === response || response.startsWith("+CME ERROR")) {101 // Unregister the prompt '> ' in case something went wrong.102 // If we don't, we get follow up errors when it is tried to again register the prompt.103 at.unregister(prompt);104 reject(response ? (command + ": " + response) : (command + ": TIMEOUT"));105 } else if (waitForLine ? (response.startsWith(waitForLine)) : ("OK" === response)) {106 resolve(waitForLine ? response : answer);107 } else {108 answer += (answer ? "\n" : "") + response;109 return processResponse;110 }111 });112 });113};114// Calculate a checksum of the file.115// Checksum is calculated by doing a XOR operation for every 2 bytes116function calculateChecksum(data) {117 var checksum = [0x00, 0x00];118 for(var i = 0; i < data.length; i+=2) {119 checksum[0] ^= data.charCodeAt(i);120 if ((i+1) >= data.length) {121 checksum[1] ^= 0x00;122 } else {123 checksum[1] ^= data.charCodeAt(i+1);124 }125 }126 var checksumAsNumber = (checksum[0] << 8) | checksum[1];127 return checksumAsNumber;128}129// Upload certificates130function uploadCertificates() {131 console.log("Connecting Cellular Modem ...");132 require("iTracker").setCellOn(true, function (usart) {133 console.log("Cellular Modem connected.");134 at = require("AT").connect(usart);135 at.debug(debug);136 sendAtCommand('AT&F0')137 .then(() => sendAtCommand('ATE0'))138 // List all files in UFS directory139 .then(() => sendAtCommand('AT+QFLST="*"'))140 .then((line) => {141 console.log("Files in file system: " + line);142 })143 // Delete all files in UFS directory144 .then(() => sendAtCommand('AT+QFDEL="*"'))145 .then( () => sendAtCommandAndWaitForPrompt(146 'AT+QFUPL="' + FILENAME_CLIENT_CERT +'",' + client_cert.length + ',100',147 1000,148 client_cert,149 '+QFUPL:'150 )151 )152 .then((line) => {153 console.log("+QFUPL line:", line, "Uploaded", FILENAME_CLIENT_CERT);154 var returnedChecksum = parseInt(line.split(',')[1], 16);155 var expectedChecksum = calculateChecksum(client_cert);156 if (returnedChecksum !== expectedChecksum) {157 throw new Error('Checksums do not match.');158 }159 })160 .then( () => sendAtCommandAndWaitForPrompt(161 'AT+QFUPL="' + FILENAME_PRIVATE_KEY + '",' + client_private_key.length + ',100',162 1000,163 client_private_key,164 '+QFUPL:'165 )166 )167 .then((line) => {168 console.log("+QFUPL line:", line, "Uploaded", FILENAME_PRIVATE_KEY);169 var returnedChecksum = parseInt(line.split(',')[1], 16);170 var expectedChecksum = calculateChecksum(client_private_key);171 if (returnedChecksum !== expectedChecksum) {172 throw new Error('Checksums do not match.');173 }174 })175 .then( () => sendAtCommandAndWaitForPrompt(176 'AT+QFUPL="' + FILENAME_TRUSTED_ROOT_CA + '",' + trusted_root_ca.length + ',100',177 1000,178 trusted_root_ca,179 '+QFUPL:'180 )181 )182 .then((line) => {183 console.log("+QFUPL line:", line, "Uploaded", FILENAME_TRUSTED_ROOT_CA);184 var returnedChecksum = parseInt(line.split(',')[1], 16);185 var expectedChecksum = calculateChecksum(trusted_root_ca);186 if (returnedChecksum !== expectedChecksum) {187 throw new Error('Checksums do not match.');188 }189 console.log("\nSuccessfully uploaded SSL certificates to BG96 module.");190 })191 .catch((err) => {192 console.log('Could not upload SSL certificates to BG96 module:', err);193 });194 });...
player.js
Source:player.js
...36 // regexes for matching player state and controller37 const stateRegExp = /BP_PlayerState_C .+?PersistentLevel\.(?<state>BP_PlayerState_C_\d+)\.PlayerName = (?<name>.+)$/;38 const controllerRegExp = /BP_PlayerState_C .+?PersistentLevel\.(?<state>BP_PlayerState_C_\d+)\.Owner = BP_PlayerController_C'.+?:PersistentLevel.(?<controller>BP_PlayerController_C_\d+)'/;39 // wait for this players' state40 const statePromise = brickadia.waitForLine(line => {41 const match = line.match(stateRegExp);42 // no match, return null43 if (!match) return null;44 const { name, state } = match.groups;45 // a player under the same name is using this state, ignore46 if (this._brikkit._players.some(p => p._connected && p._username === this._username && state === p._state)) {47 return null;48 }49 // return the state if the name matches50 return name === this._username ? state : null;51 });52 // request all states and players from brickadia53 brickadia.write(`GetAll BRPlayerState PlayerName\n`);54 const state = await statePromise;55 // wait for this players' controller56 const controllerPromise = brickadia.waitForLine(line => {57 const match = line.match(controllerRegExp);58 // if no match, return null59 if (!match) return null;60 return match.groups.state === state ? match.groups.controller : null;61 });62 // request the owner for this state63 brickadia.write(`GetAll BRPlayerState Owner Name=${state}\n`);64 const controller = await controllerPromise;65 if (!controller || !state)66 return null;67 // the controller and state exist, so this player is connected68 this._state = state;69 this._controller = controller;70 this._connected = true;71 return controller;72 }73 // get player's position74 async getPosition() {75 if (!this._brikkit)76 return null;77 const controller = this._controller || await this.getController();78 if (!controller)79 return;80 const brickadia = this._brikkit._brickadia;81 // regexes for matching player state and controller82 const pawnRegExp = /BP_PlayerController_C .+?PersistentLevel\.(?<controller>BP_PlayerController_C_\d+)\.Pawn = BP_FigureV2_C'.+?:PersistentLevel.(?<pawn>BP_FigureV2_C_\d+)'/;83 const posRegExp = /CapsuleComponent .+?PersistentLevel\.(?<pawn>BP_FigureV2_C_\d+)\.CollisionCylinder\.RelativeLocation = \(X=(?<x>[\d\.-]+),Y=(?<y>[\d\.-]+),Z=(?<z>[\d\.-]+)\)/;84 // wait for this players' pawn85 const pawnPromise = brickadia.waitForLine(line => {86 const match = line.match(pawnRegExp);87 // if no match, return null88 if (!match) return null;89 return match.groups.controller === controller ? match.groups.pawn : null;90 });91 // request all states and players from brickadia92 brickadia.write(`GetAll BP_PlayerController_C Pawn Name=${controller}\n`);93 const pawn = await pawnPromise;94 // wait for this players' pawn95 const posPromise = brickadia.waitForLine(line => {96 const match = line.match(posRegExp);97 // if no match, return null98 if (!match) return null;99 const { x, y, z } = match.groups;100 return match.groups.pawn === pawn ? [x, y, z].map(Number) : null;101 });102 // request the owner for this state103 brickadia.write(`GetAll SceneComponent RelativeLocation Name=CollisionCylinder Outer=${pawn}\n`);104 const pos = await posPromise;105 if (!pawn || !pos)106 return null;107 // the player exists, return the position108 return pos;109 }...
avd_test.js
Source:avd_test.js
...31 }32 });33 proc.stdout.on('data', data => console.log(data.toString()));34 proc.stderr.on('data', data => console.log(data.toString()));35 await waitForLine(proc, /boot completed/);36 const context = await _clank.launchPersistentContext('');37 const [page] = context.pages();38 await page.goto('data:text/html,<title>Hello world</title>');39 assert(await page.title() === 'Hello world');40 await context.close();41 process.exit(0);42})();43async function waitForLine(proc, regex) {44 return new Promise((resolve, reject) => {45 const rl = readline.createInterface({ input: proc.stdout });46 const failError = new Error('Process failed to launch!');47 rl.on('line', onLine);48 rl.on('close', reject.bind(null, failError));49 proc.on('exit', reject.bind(null, failError));50 proc.on('error', reject.bind(null, failError));51 function onLine(line) {52 const match = line.match(regex);53 if (!match)54 return;55 resolve(match);56 }57 });...
keyboard.js
Source:keyboard.js
1/////editor2//var doCommand = null;3var enterFlag = false;4window.doOutput = false;5const display = require("/js/display.js");6var eline = "> ";7var lastWaiter = null;8var key = function(k) {9 //console.log("KK", k);10 if (k == 7) {11 //recall last12 eline += lastWaiter;13 } else if (k == 13) {14 //if (doOutput && eline.length > 2) display.clearSameLine(eline + " ");15 //if (doOutput) display.clearSameLine(eline + " ");16 waiter = eline.substr(2).trim();17 enterFlag = true;18 if (waiter) lastWaiter = eline.substr(2).trim();19 //console.log("WA", waiter);20 //doCommand(eline.substr(2).trim());21 eline = "> ";22 return;23 } else if (k == 8) {24 if (eline.length > 2) {25 eline = eline.substr(0, eline.length - 1);26 if (window.doOutput) display.printSameLine(eline + "_ ");27 }28 } else if (!k) {29 eline = "> ";30 //console.log("KEY 0", window.doOutput, eline);31 if (window.doOutput) display.printSameLine(eline + "_ ");32 } else {33 eline += String.fromCharCode(k);34 }35 if (window.doOutput) display.printSameLine(eline + "_");36};37var waiter = null;38var waitForLine = () => {39 var line = waiter;40 waiter = null;41 return line;42};43var wasEnterPressed = () => {44 if (enterFlag) {45 enterFlag = false;46 return true;47 }48 return false;49};50module.exports = {51 init() {},52 key,53 doOutput(d) {54 window.doOutput = d;55 },56 waitForLine,57 wasEnterPressed...
start-with-folder.js
Source:start-with-folder.js
...12 t.error(err)13 t.equal(Object.keys(instance.services).length, 2, 'number of services')14 t.ok(instance.services.a, 'service a exists')15 t.ok(instance.services.b, 'service b exists')16 waitForLine(instance.services.a, `a (${instance.services.a.id}): hello from a`)17 waitForLine(instance.services.b, `b (${instance.services.b.id}): hello from b`)18 function waitForLine (s, expected) {19 s.output20 .pipe(split())21 .once('data', (line) => {22 line = chalk.stripColor(line)23 t.equal(line, expected, 'line matches')24 })25 }...
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.waitForLine('input[name="q"]');7 await browser.close();8})();
Using AI Code Generation
1const playwright = require('playwright');2(async () => {3 const browser = await playwright.chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 const [consoleMessage] = await Promise.all([7 page.waitForEvent('console'),8 page.evaluate(() => console.log('hello', 5, {foo: 'bar'})),9 ]);10 console.log(consoleMessage.text());11 await browser.close();12})();13const playwright = require('playwright');14(async () => {15 const browser = await playwright.chromium.launch();16 const context = await browser.newContext();17 const page = await context.newPage();18 const [consoleMessage] = await Promise.all([19 page.waitForEvent('console'),20 page.evaluate(() => console.log('hello', 5, {foo: 'bar'})),21 ]);22 console.log(consoleMessage.text());23 await browser.close();24})();25const playwright = require('playwright');26(async () => {27 const browser = await playwright.chromium.launch();28 const context = await browser.newContext();29 const page = await context.newPage();30 const [consoleMessage] = await Promise.all([31 page.waitForEvent('console'),32 page.evaluate(() => console.log('hello', 5, {foo: 'bar'})),33 ]);34 console.log(consoleMessage.text());35 await browser.close();36})();37const playwright = require('playwright');38(async () => {39 const browser = await playwright.chromium.launch();40 const context = await browser.newContext();41 const page = await context.newPage();42 const [consoleMessage] = await Promise.all([43 page.waitForEvent('console'),44 page.evaluate(() => console.log('hello', 5, {foo: 'bar'})),45 ]);46 console.log(consoleMessage.text());47 await browser.close();48})();49const playwright = require('
Using AI Code Generation
1const playwright = require('playwright');2(async () => {3 const browser = await playwright.chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 const console = page.context().console();7 const message = await console.waitForLine(line => line.text().includes('API'));8 console.log(message.text());9 await browser.close();10})();11const playwright = require('playwright');12(async () => {13 const browser = await playwright.chromium.launch();14 const context = await browser.newContext();15 const page = await context.newPage();16 const console = page.context().console();17 const message = await console.waitForLine(line => line.text().includes('API'));18 console.log(message.text());19 await browser.close();20})();21const playwright = require('playwright');22(async () => {23 const browser = await playwright.chromium.launch();24 const context = await browser.newContext();25 const page = await context.newPage();26 const console = page.context().console();27 const message = await console.waitForLine(line => line.text().includes('API'));28 console.log(message.text());29 await browser.close();30})();31const playwright = require('playwright');32(async () => {33 const browser = await playwright.chromium.launch();34 const context = await browser.newContext();35 const page = await context.newPage();36 const console = page.context().console();37 const message = await console.waitForLine(line => line.text().includes('API'));38 console.log(message.text());39 await browser.close();40})();41const playwright = require('playwright');42(async () => {43 const browser = await playwright.chromium.launch();44 const context = await browser.newContext();45 const page = await context.newPage();
Using AI Code Generation
1const { Playwright } = require('playwright-core/lib/server/playwright.js');2const playwright = new Playwright();3const browser = await playwright.chromium.launch({ headless: false });4const context = await browser.newContext();5const page = await context.newPage();6const { Playwright } = require('playwright-core/lib/server/playwright.js');7const playwright = new Playwright();8const browser = await playwright.chromium.launch({ headless: false });9const context = await browser.newContext();10const page = await context.newPage();11const { Playwright } = require('playwright-core/lib/server/playwright.js');12const playwright = new Playwright();13const browser = await playwright.chromium.launch({ headless: false });14const context = await browser.newContext();15const page = await context.newPage();16const { Playwright } = require('playwright-core/lib/server/playwright.js');17const playwright = new Playwright();18const browser = await playwright.chromium.launch({ headless: false });19const context = await browser.newContext();20const page = await context.newPage();21const { Playwright } = require('playwright-core/lib/server/playwright.js');22const playwright = new Playwright();23const browser = await playwright.chromium.launch({ headless: false });24const context = await browser.newContext();25const page = await context.newPage();26const { Playwright } = require('playwright-core/lib/server/playwright.js');27const playwright = new Playwright();28const browser = await playwright.chromium.launch({ headless: false });29const context = await browser.newContext();30const page = await context.newPage();
Using AI Code Generation
1const playwright = require('playwright');2const { waitForLine } = require('playwright/lib/internal/stdio');3(async () => {4 const browser = await playwright.chromium.launch({headless: false});5 const context = await browser.newContext();6 const page = await context.newPage();7 const waitforline = await waitForLine();8 console.log(waitforline);9 await browser.close();10})();
Using AI Code Generation
1const { waitForLine } = require('@playwright/test/lib/server/processLauncher');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch({headless: false});5 const context = await browser.newContext();6 const page = await context.newPage();7 await page.click('text=Get started');8 await page.close();9 await context.close();10 await browser.close();11})();12const { test } = require('@playwright/test');13test('should wait for line', async ({ page }) => {14 await page.click('text=Get started');15 await page.waitForSelector('text=Docs');16});
Using AI Code Generation
1const { _electron } = require('playwright');2(async () => {3 const { electron } = _electron;4 const app = await electron.launch({ args: ['path/to/app'] });5 const page = await app.firstWindow();6 const { waitForLine } = require('playwright/lib/server/electron');7 await waitForLine(page, 'Listening on port 3000');8 await app.close();9})();
Using AI Code Generation
1const { waitForLine } = require('playwright/lib/internal/stdio');2(async () => {3 await waitForLine(process.stdout, 'Server is listening');4 console.log('Server is listening');5})()6const { waitForLine } = require('playwright/lib/internal/stdio');7(async () => {8 await waitForLine(process.stdout, 'Server is listening');9 console.log('Server is listening');10})()11const { waitForLine } = require('playwright/lib/internal/stdio');12(async () => {13 await waitForLine(process.stdout, 'Server is listening');14 console.log('Server is listening');15})()16const { waitForLine } = require('playwright/lib/internal/stdio');17(async () => {18 await waitForLine(process.stdout, 'Server is listening');19 console.log('Server is listening');20})()21const { waitForLine } = require('playwright/lib/internal/stdio');22(async () => {23 await waitForLine(process.stdout, 'Server is listening');24 console.log('Server is listening');25})()26const { waitForLine } = require('playwright/lib/internal/stdio');27(async () => {28 await waitForLine(process.stdout, 'Server is listening');29 console.log('Server is listening');30})()31const { waitForLine } = require('playwright/lib/internal/stdio');32(async () => {33 await waitForLine(process.stdout, 'Server is listening');34 console.log('Server is listening');35})()36const { waitForLine } = require('playwright/lib/internal/stdio');37(async () => {38 await waitForLine(process.stdout, 'Server is listening');39 console.log('Server is listening');40})()41const { waitForLine } = require('playwright/lib/internal/stdio');
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!