Skip to content

Commit

Permalink
Replace _sendAndHandleProtobufRequest with sendProtobufRequest for si…
Browse files Browse the repository at this point in the history
…mpler return object
  • Loading branch information
keeramis committed May 29, 2024
1 parent 504c86a commit a971ab0
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 139 deletions.
3 changes: 3 additions & 0 deletions src/wifi-device-legacy.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
* However, it can still be used on Paticle Photon devices running
* Device OS systems firmware from 0.8.0 to pre 2.0.0.
*/

// TODO: Remove the legacy behavior!

const { Request } = require('./request');
const { fromProtobufEnum, fromProtobufMessage, toProtobufMessage } = require('./protobuf-util');
const { definitions: proto } = require('@particle/device-os-protobuf');
Expand Down
214 changes: 75 additions & 139 deletions src/wifi-device.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
const DeviceOSProtobuf = require('@particle/device-os-protobuf');
const { TimeoutError } = require('./error');
const { definitions: proto } = require('@particle/device-os-protobuf');

/**
* Wi-Fi security types.
*
* @enum {String}
*/
const WiFiSecurity = fromProtobufEnum(proto.wifi.Security, {

Check failure on line 9 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v12)

'fromProtobufEnum' is not defined

Check failure on line 9 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v14)

'fromProtobufEnum' is not defined

Check failure on line 9 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v16)

'fromProtobufEnum' is not defined
NO_SECURITY : 'NONE',
WEP : 'WEP',
WPA_PSK : 'WPA_PSK',
WPA2_PSK : 'WPA2_PSK',
WPA_WPA2_PSK : 'WPA_WPA2_PSK',
WPA3_PSK : 'WPA3_PSK',
WPA2_WPA3_PSK : 'WPA2_WPA3_PSK',
});

/**
* Wi-Fi device.
Expand All @@ -12,83 +27,67 @@ const { TimeoutError } = require('./error');
const WifiDevice = base => class extends base {
/**
* Perform WiFi scan for Gen 3+ devices
*

Check failure on line 30 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v12)

Trailing spaces not allowed

Check failure on line 30 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v14)

Trailing spaces not allowed

Check failure on line 30 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v16)

Trailing spaces not allowed
* Supported platforms:
* - Gen 3
* - Gen 4
*

Check failure on line 34 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v12)

Trailing spaces not allowed

Check failure on line 34 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v14)

Trailing spaces not allowed

Check failure on line 34 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v16)

Trailing spaces not allowed
* @param {Object} options See sendControlRequest(), same options are here.
* @return {Promise[Object]} - Each object in array has these properties: ssid, bssid, security, channel, rssi. See Network protobuf message from https://github.com/particle-iot/device-os-protobuf for more details.
*/
async scanWifiNetworks(options) {
const result = await this._sendAndHandleProtobufRequest(
const result = await this.sendProtobufRequest(
'wifi.ScanNetworksRequest',
{},
options
);

let returnThis;
if (result.pass) {
returnThis = result.replyObject.networks.map((network) => {
return {
ssid: network.ssid || null, // can be blank for hidden networks
bssid: network.bssid.toString('hex'), // convert buffer to hex string
security: this._mapSecurityValueToString(network.security),
channel: network.channel,
rssi: network.rssi
};
});
} else {
returnThis = [];
}
return returnThis;
}

// Internal helper that transforms int or undefined into a string
// for security field from scanWifiNetworks
_mapSecurityValueToString(value) {
if (value === undefined) {
return 'UNKNOWN';
}
const wifiSecurityEnum = DeviceOSProtobuf.getDefinition('wifi.Security').message;
const firstMatchingKey = Object.keys(wifiSecurityEnum).find(key => wifiSecurityEnum[key] === value);
if (firstMatchingKey === undefined) {
return 'UNKNOWN';
} else {
return firstMatchingKey;
}
return result.networks.map((network) => {
return {
ssid: network.ssid || null, // can be blank for hidden networks
bssid: network.bssid.toString('hex'), // convert buffer to hex string
security: WiFiSecurity.fromProtobuf(network.security),
channel: network.channel,
rssi: network.rssi
};
});
}

/**
* Join a new WiFi network for Gen 3+ devices.
*
* Note, there are known bugs with this method/Device OS:
* - sc-96270: where P2's don't do anything with bssid or security fields; so cannot connect to hidden networks
* - sc-96826: Connecting to open network without passsword does not work
*
* Warning: May not work for hidden networks due to certain bugs in the device-os.
*

Check failure on line 60 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v12)

Trailing spaces not allowed

Check failure on line 60 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v14)

Trailing spaces not allowed

Check failure on line 60 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v16)

Trailing spaces not allowed
* Supported platforms:
* - Gen 4: Supported on P2 since Device OS 3.x
* - Gen 3
* - Gen 4
*

Check failure on line 64 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v12)

Trailing spaces not allowed

Check failure on line 64 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v14)

Trailing spaces not allowed

Check failure on line 64 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v16)

Trailing spaces not allowed
* @param {string} ssid - SSID of Wifi Network
* @param {string} security - Security of Wifi network
* @param {string} password - Password of Wifi network, if not set will not use security
* @param {Object} options See sendControlRequest(), same options are here.
* @return {ProtobufInteraction} -
* @return {ProtobufInteraction} - empty response
*/
async joinNewWifiNetwork({ ssid, password = null }, options) {
async joinNewWifiNetwork({ ssid, security, password = null }, options) {
let dataPayload;
if (password === null) {
dataPayload = {
ssid,
bssid: null,
security: 0 // Security.NO_SECURITY
};
// throw new Error('joinNewWifiNetwork() does not currently support connecting to networks without a password/security, sc-TODO');
} else {
dataPayload = {
ssid,
bssid: null,
security: null,
security: security ? WiFiSecurity.toProtobuf(security) : null,
credentials: {
type: 1, // CredentialsType.PASSWORD
password
},
};
}
return await this._sendAndHandleProtobufRequest(
return await this.sendProtobufRequest(
'wifi.JoinNewNetworkRequest',
dataPayload,
options
Expand All @@ -98,20 +97,16 @@ const WifiDevice = base => class extends base {
/**
* Join a known WiFi network for Gen 3+ devices.
*
* Note, there are known bugs with this method/Device OS:
* - sc-96270: where P2's don't do anything with bssid or security fields; so cannot connect to hidden networks
* - sc-96826: Connecting to open network without passsword does not work
*
* Supported platforms:
* - Gen 4: Supported on P2 since Device OS 3.x
* - Gen 4: Supported on M-SoM since Device OS 5.x
* - Gen 3
* - Gen 4
*

Check failure on line 103 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v12)

Trailing spaces not allowed

Check failure on line 103 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v14)

Trailing spaces not allowed

Check failure on line 103 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v16)

Trailing spaces not allowed
* @param {string} ssid - SSID of Wifi Network
* @param {string} password - Password of Wifi network, if not set will not use security
* @param {Object} options See sendControlRequest(), same options are here.
* @return {ProtobufInteraction} -
* @return {ProtobufInteraction} - empty response
*/
async joinKnownWifiNetwork({ ssid }, options) {
return await this._sendAndHandleProtobufRequest(
return await this.sendProtobufRequest(
'wifi.JoinKnownNetworkRequest',
{ ssid },
options
Expand All @@ -120,54 +115,55 @@ const WifiDevice = base => class extends base {

/**
* Gets the list of networks for Gen 3+ devices.
*
* Note, there are known bugs with this method/Device OS:
* - sc-96270: where P2's don't do anything with bssid or security fields; so cannot connect to hidden networks
* - sc-96826: Connecting to open network without passsword does not work
*
*

Check failure on line 118 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v12)

Trailing spaces not allowed

Check failure on line 118 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v14)

Trailing spaces not allowed

Check failure on line 118 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v16)

Trailing spaces not allowed
* Supported platforms:
* - Gen 4: Supported on P2 since Device OS 3.x
* - Gen 4: Supported on M-SoM since Device OS 5.x
* @param {string} ssid - SSID of Wifi Network
* @param {string} password - Password of Wifi network, if not set will not use security
* - Gen 3
* - Gen 4
*

Check failure on line 122 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v12)

Trailing spaces not allowed

Check failure on line 122 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v14)

Trailing spaces not allowed

Check failure on line 122 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v16)

Trailing spaces not allowed
* @param {Object} options See sendControlRequest(), same options are here.
* @return {ProtobufInteraction} -
* @return {ProtobufInteraction} - An array of known networks (ssid, security, credentialsType). See GetKnownNetworksReply from https://github.com/particle-iot/device-os-protobuf/blob/main/control/wifi_new.proto
*/
async listWifiNetworks(options) {
return await this._sendAndHandleProtobufRequest(
return await this.sendProtobufRequest(
'wifi.GetKnownNetworksRequest',
options
);
}

/**
* Gets the list of networks for Gen 3+ devices.
*
* Note, there are known bugs with this method/Device OS:
* - sc-96270: where P2's don't do anything with bssid or security fields; so cannot connect to hidden networks
* - sc-96826: Connecting to open network without passsword does not work
* Removes a Wi-Fi network
*
* Supported platforms:
* - Gen 4: Supported on P2 since Device OS 3.x
* - Gen 4: Supported on M-SoM since Device OS 5.x
* - Gen 3
* - Gen 4
*

Check failure on line 139 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v12)

Trailing spaces not allowed

Check failure on line 139 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v14)

Trailing spaces not allowed

Check failure on line 139 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v16)

Trailing spaces not allowed
* @param {string} ssid - SSID of Wifi Network
* @param {string} password - Password of Wifi network, if not set will not use security
* @param {Object} options See sendControlRequest(), same options are here.
* @return {ProtobufInteraction} -
* @return {ProtobufInteraction} - empty response
*/
async removeWifiNetwork({ ssid }, options) {
const dataPayload = {
ssid
};
return await this._sendAndHandleProtobufRequest(
return await this.sendProtobufRequest(
'wifi.RemoveKnownNetworkRequest',
dataPayload,
options
);
}

/**
* Gets the currently connected Wi-Fi network for Gen 3+ devices.
*
* Supported platforms:
* - Gen 3
* - Gen 4
*

Check failure on line 161 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v12)

Trailing spaces not allowed

Check failure on line 161 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v14)

Trailing spaces not allowed

Check failure on line 161 in src/wifi-device.js

View workflow job for this annotation

GitHub Actions / Test (Node.js v16)

Trailing spaces not allowed
* @param {Object} options See sendControlRequest(), same options are here.
* @return {Promise[Object]} - ssid, bssid, channel, rssi. See GetCurrentNetworkReply from https://github.com/particle-iot/device-os-protobuf/blob/main/control/wifi_new.proto
*/
async getCurrentWifiNetwork(options) {
return await this._sendAndHandleProtobufRequest(
return await this.sendProtobufRequest(
'wifi.GetCurrentNetworkRequest',
{},
options
Expand All @@ -177,16 +173,14 @@ const WifiDevice = base => class extends base {
/**
* Set a new WiFi network for Gen 3+ devices.
*
* Note, there are known bugs with this method/Device OS:
* - sc-96270: where P2's don't do anything with bssid or security fields; so cannot connect to hidden networks
* - sc-96826: Connecting to open network without passsword does not work
*
* Supported platforms:
* - Gen 4: Supported on P2 since Device OS 5.8.2
*
* @param {string} ssid - SSID of Wifi Network
* @param {string} security - Security of Wifi network
* @param {string} password - Password of Wifi network, if not set will not use security
* @param {Object} options See sendControlRequest(), same options are here.
* @return {ProtobufInteraction} -
* @return {ProtobufInteraction} - empty response
*/
async setWifiCredentials({ ssid, security, password = null }, options) {
let dataPayload;
Expand All @@ -196,7 +190,6 @@ const WifiDevice = base => class extends base {
bssid: null,
security: 0 // Security.NO_SECURITY
};
throw new Error('joinNewWifiNetwork() does not currently support connecting to networks without a password/security, sc-TODO');
} else {
dataPayload = {
ssid,
Expand All @@ -208,7 +201,7 @@ const WifiDevice = base => class extends base {
},
};
}
return await this._sendAndHandleProtobufRequest(
return await this.sendProtobufRequest(
'wifi.SetNetworkCredentialsRequest',
dataPayload,
options
Expand All @@ -219,75 +212,18 @@ const WifiDevice = base => class extends base {
* Clear Wifi networks for Gen 3+ devices
*
* @param {Object} options See sendControlRequest(), same options are here.
* @return {ProtobufInteraction} -
* @return {ProtobufInteraction} - empty response
*/

async clearWifiNetworks(options) {
return await this._sendAndHandleProtobufRequest(
return await this.sendProtobufRequest(
'wifi.ClearKnownNetworksRequest',
{},
options
);
}

/**
* Returned by _sendAndHandleProtobufRequest
* @typedef {Object} ProtobufInteraction
* @property {boolean} pass - Indicates whether the request/reply succeeded
* @property {undefined|*} replyObject - An instance created via the protobuf replyMessage constructor
* @property {undefined|string} error - If pass is false, will be a string explaining failure reason
*/

/**
* Wraps .sendProtobufRequest, handles validation and error handling in opinionated way
* to DRY up code in higher level methods
*
* @private could conceivably be added to public api in device.js later.
*
* @param {String} protobufMessageName - name of protobuf message see DeviceOSProtobuf.getDefinitions() to possible values
* @param {Object} protobufMessageData - An object of key/values to encode into the protobuf message
* @param {Object} options See sendControlRequest(), same options are here.
* @return {ProtobufInteraction} - Summary of request/reply object
* @throws {*} - Throws errors considered abnormal, catches TimeoutError which is considered normal type of
* failure/did-not-suceed for many Device OS requests
*/
async _sendAndHandleProtobufRequest(protobufMessageName, protobufMessageData = {}, options) {
const protobufDefinition = DeviceOSProtobuf.getDefinition(protobufMessageName);
const returnThis = {};

let replyObject;
try {
replyObject = await this.sendProtobufRequest(
protobufMessageName,
protobufMessageData,
options
);
} catch (error) {
if (error instanceof TimeoutError) {
returnThis.pass = false;
if (options && options.timeout) {
returnThis.error = `Request timed out, exceeded ${options.timeout}ms`;
} else {
returnThis.error = `Request timed out, exceeded default timeout`;
}
return returnThis;
}
throw error;
}

// Example:
// replyObject.constructor.name might be 'JoinNewNetworkReply'
// for a protobufMessageName to 'wifi.JoinNewNetworkRequest'
if (replyObject && replyObject.constructor &&
replyObject.constructor.name === protobufDefinition.replyMessage.name) {
returnThis.pass = true;
returnThis.replyObject = replyObject;
} else {
returnThis.pass = false;
returnThis.error = `Device did not return a valid reply. expected=${protobufDefinition.replyMessage.name} actual=${JSON.stringify(replyObject)}`;
}
return returnThis;
}
};

const WifiSecurityEnum = DeviceOSProtobuf.getDefinition('wifi.Security').message;
Expand Down

0 comments on commit a971ab0

Please sign in to comment.