Continue
Hole io max size classic mode
With our Hole.io MOD APK (Unlimited Points/ XP), You can download it for Free from our website. You will get Unlimited Points and Unlimited XP resources on your game account. Moreover, you will Unlock All Skins and have the Size Up On function. Hole.io Mod Apk Information: App NameHole.io Mod Apk PlatformAndroid Size79M Mod
FeaturesUnlimited XP & Unlimited Points. Unlock All Skins, Size Up On Version1.10.4 CategoryArcade Root Required?No PriceFree Get it on Unlimited XP Unlimited Points All Skins Unlocked Size Up On Free to download Totally Safe Compatible with all Android versions Hole.io Mod APK file is very easy to install Autoupdate No need to root your Android device! You may also try our Slither.io MOD APK (Invisible Skin, God Mode). Unlock All Skins with Hole.io MOD Skins are the appearance you use in the game. The first skin is the Hearth Skin: Play again tomorrow (play the game for 2 days in a row). The second skin: Mouse Skin is normally gained only if you eat 75 buildings. For the Fidget Spinner Skin, you must play 7 consecutive days. For the Giant Worm Mouth Skin, you have to eat 50 cars in classic mode. The Shark Skin is unlocked after you eat 100 people cops and for Whale Skin 15 cops in classic mode. Get Unlimited XP with our Hole.io mod apk. Get Godzilla Skin after you finish in the first place a classic mode. Score 1 000 points in classic mode and get the Cauldron Skin and 2 000 points for the Rainbow Skin. Download Hole.io MOD APK to get unlimited points. Kill 10 holes in classic mode for the Black Hole Skin. Reach the max size 3 times in classic mode for the Pig Skin. For the Cat Skin, you need Silver Rank (level 3) and for the Golden Cat Skin, you have to reach the Gold Rank (level 6). All the skins will be unlocked and available to be used with our Hole.io MOD apk. For the Black Cat Skin, Diamond Rank (level 9). At the Platinum Rank (level 12) you can get the Bat Skin. Reach the Master Rank (level 15) for the Devil Bat Skin. Volcano Crater Skin is unlocked at level 17, the last rank. You will also get the Rabit Skin: Zoo Escape and the Zombie Skin: be the serial killer. Last but not least, get the Frog Skin: One for Hole, Hole for One. Below is the list with all the skins available to use right after you download and install the Hole.io mod APK. Hearth Skin Mouse Skin Fidget Spinner Skin Giant Worm Mouth Skin Whale Skin Shark Skin Godzilla Skin Cauldron Skin Rainbow Skin Black Hole Skin Pig Skin Golden Cat Skin Cat Skin Black Cat Skin Bat Skin Devil Bat Skin Volcano Crater Skin Rabbit Skin Zombie Skin Frog Skin About the game Science geeks would love it for its concept and framework. But, it has been designed in a way that would enthrall every single user because of the execution of the idea behind the introduction of this game. The storyline is set around an all-encompassing black hole that goes about a fictional town and swallows in the objects. The objective of Hole.io is to create the biggest hole. It functions like the black hole we have all heard and read about. The player is playing with the purpose of showing the inhabitants of the town that he/she has the largest black hole with a maximum expanded version to engulf almost any object. The gameplay modes There are four modes available and they are as follows: The classic mode comes with a two-minute timer battle to engulf and expand as much as possible. Battle mode has no timer and the aim is to last in the game and become the only surviving hole in town. The solo run mode also has a two-minute timer added as a part, but the feature has a twist because there won’t be any opponents so it’s just you and your power to engulf objects. Local Multiplayer mode needs a strong Bluetooth connection between the players because as the name suggests, it is meant to be a hurdle in the form of competition between you and your friend, battling with the same goal in mind. The disadvantage of the game There is no music to create the vibe or atmosphere of the battle between black holes. But you can play music in the background with the help of an application like Pandora. Many times, this disappoints users. Other than this disadvantage, this game has succeeded in making gamers feel engaged and hooked to the game at all times. Also, take a look at Slither.io MOD APK (Invisible Skins, God Mode). How to download and install Hole.io MOD APK on Android The mod apk file is very easy to install: Just click the download button below Download MOD APK Wait until the file is downloaded then open it Install Hole.io Mod Apk file on your Android device Follow the instructions inside Start and Enjoy the Mod Make sure you checked the box for – ‘Allow installs from other sources than the Play Store’ in your settings 1.14.0 February 12, 2021 Bug fixes 1.13.0 February 12, 2021 Minor bug fixes 1.11.0 October 19, 2020 Bug fixes 1.10.5 October 19, 2020 Bug fixes 1.10.4 August 21, 2020 Bug fixes 1.10.3 August 7, 2020 Bug fixes 1.10.2 August 4, 2020 Bug fixes 1.9.1 July 17, 2020 Bug fixes 1.8.0 May 10, 2020 Bug fixes 1.7.7 April 3, 2020 Bug fixes 1.6.9 February 6, 2020 Bug fixes Varies with device February 6, 2020 Bug fixes 1.6.8 November 25, 2019 Bug fixes 1.6.7 October 31, 2019 Bug fixes 1.6.5 October 17, 2019 Bug fixes 1.6.2 July 5, 2019 Bug fixes 1 August 8, 2021 Bug fixes 1.6.2 July 5, 2019 Bug fixes 1 August 8, 2021 Bug fixes 1.6.2 July 5, 2019 Bug fixes 1 August 8, 2021 Bug fixes 1.6.2 July 5, 2019 Bug fixes 1 August 8, 2021 Bug fixes 1.6.2 July 5, 2019 Bug fixes 1 August 8, 2021 Bug fixes 1.6.2 July 5, 2019 Bug fixes 1 August 8, 2021 Bug fixes 1.6.2 July 5, 2019 Bug fixes 1.6.1 February 1, 2019 Bug fixes 1 August 8, 2021 Bug fixes 1.6.1 February 1, 2019 Bug fixes 1.6.0 January 18, 2019 PATCH NOTES:- Performance improve on low devices- The futurist scifi map is now available- Bug fixesThank you for playing! 1.5.2 November 28, 2018 Bug fixes 1.5.1 November 13, 2018 PATCH NOTES:- Minor bug fixesThank you for playing! You're viewing an iOS app. The most addictive game! Enter the arena and face the other holes in a fierce battle. Eat everything in sight with your black hole and expand it to eat more! Show them who is the biggest hole in town! You are viewing the single-page version of the Device OS API reference manual. It is also available divided into small sections if you prefer that style. Small sections also work better on mobile devices and small tablets. Cloud FunctionsOverview of API field limits Limits are in bytes of UTF-8 encoded characters. 2On Gen 2 devices (Photon, P1, Electron, E Series), the limit is 864 characters, 3On Gen 3 devices (Argon, Boron, B Series SoM, Tracker SoM) the limit is 1024 characters. The 0.8.0 - 2.x column includes all 2.x LTS versions. Higher limits will not be back-ported to 2.x LTS. Instead of hardcoding these values, you should use these definitions: particle::protocol::MAX_VARIABLE_KEY_LENGTH
particle::protocol::MAX_VARIABLE_VALUE_LENGTH particle::protocol::MAX_FUNCTION_KEY_LENGTH particle::protocol::MAX_FUNCTION_ARG_LENGTH particle::protocol::MAX_EVENT_NAME_LENGTH particle::protocol::MAX_EVENT_DATA_LENGTH Additionally, some older Boron and B Series SoM with a SARA-R410M-02B modem (LTE Cat M1) may have a limit of 782 bytes instead of 1024 bytes, see Particle.maxEventDataSize() for more information. Particle.variable()Expose a variable through the Cloud so that it can be called with GET /v1/devices/{DEVICE_ID}/{VARIABLE}. Returns a success value - true when the variable was registered. Particle.variable registers a variable, so its value can be retrieved from the cloud in the future. You only call Particle.variable once per variable, typically passing in a global variable. You can change the value of the underlying global variable as often as you want; the value is only retrieved when requested, so simply changing the global variable does not use any data. You do not call
Particle.variable when you change the value. // EXAMPLE USAGE bool flag = false; int analogvalue = 0; double tempC = 0; char *message = "my name is particle"; String aString; void setup() { Particle.variable("flag", flag); Particle.variable("analogvalue", analogvalue); Particle.variable("temp", tempC); if (Particle.variable("mess", message) == false) { // variable not registered! } Particle.variable("mess2", aString); pinMode(A0, INPUT); } void loop() { // Read the analog value of the sensor (TMP36) analogvalue = analogRead(A0); // Convert the reading into degree Celsius tempC = (((analogvalue * 3.3) / 4095) - 0.5) * 100; delay(200); } Each variable retrieval uses one Data Operation from your monthly or yearly quota. Setting the variable does not use Data Operations. Up to 20 cloud variables may be registered and each variable name is limited to a maximum of 12 characters (prior to 0.8.0), 64 characters (since 0.8.0). Note: Only use letters, numbers, underscores and dashes in variable names. Spaces and special characters may be escaped by different tools and libraries causing unexpected results. Variables can only be read using the Particle API, or tools that use the API, like the console, CLI, and mobile apps. It's not possible to directly read a variable from another device, even on the same account. Publish and subscribe can be used if you need device-to-device
communication. For non-product devices, only the account that has claimed the device can read variable values from it. For product devices, if the device is claimed, the device owner's account can read variable values from it. Additionally, the product owner can read variable values whether the device is claimed or not. When using the default AUTOMATIC system mode, the cloud variables must be registered in the setup() function. The information about registered variables will be sent to the cloud when the setup() function has finished its execution. In the SEMI_AUTOMATIC and MANUAL system modes, the variables must be registered before Particle.connect() is called. Before 1.5.0: Variable and function registrations are only sent up once, about 30 seconds after connecting to the cloud. When using the AUTOMATIC system mode, make sure you register your cloud variables as early as possible in the setup() function, before you do any lengthy operations, delays, or things like waiting for a key press. Calling Particle.variable() after the registration information has been sent does not re-send the request and the variable will not work. String data has a maximum size of 255 to 1024 bytes of UTF-8 characters; see API Field Limits as the limit varies depending on Device OS version and sometimes the device. String variables must be UTF-8 encoded. You cannot send arbitrary binary data or other character sets like ISO-8859-1. If you need to send binary data you can use a text-based encoding like Base64. Prior to 0.4.7 firmware, variables were defined with an additional 3rd parameter to specify the data type of the variable. From 0.4.7 onward, the system can infer the type from the actual variable. Additionally, the
variable address was passed via the address-of operator (&). With 0.4.7 and newer, this is no longer required. // EXAMPLE USAGE - pre-0.4.7 syntax bool flag = false; int analogvalue = 0; double tempC = 0; char *message = "my name is particle"; void setup() { Particle.variable("flag", &flag, BOOLEAN); Particle.variable("analogvalue", &analogvalue, INT); Particle.variable("temp", &tempC, DOUBLE); if (Particle.variable("mess", message, STRING) == false) { // variable not registered! } pinMode(A0, INPUT); } There are four supported data types: BOOLEAN INT DOUBLE STRING (UTF-8 encoded characters) # EXAMPLE REQUEST IN TERMINAL # Device ID is 0123456789abcdef # Your access token is 123412341234 curl " curl " curl " curl " # In return you'll get something like this: false 960 27.44322344322344 my name is particle Particle.variable() - calculatedSince 1.5.0: It is also possible to register a function to compute a cloud variable. This can be more efficient if the computation of a variable takes a lot of CPU or other resources. It can also be an alternative to using a Particle.function(). A function is limited to a single int (32-bit) return value, but you can return bool, double, int, String from a Particle.variable. String data has a maximum size of 255 to 1024 bytes of UTF-8 characters; see API Field Limits as the limit varies depending on Device OS version and sometimes the device. Such a function should return a value of one of the supported variable types and take no arguments. The function will be called only when the value of the variable is requested. The callback function is called application loop thread context, between calls to loop(), during Particle.process(), and delay(). // EXAMPLE USAGE - registering functions as cloud variables bool flag() { return false; } int analogvalue() { // Read the analog value of the sensor (TMP36) return analogRead(A0); } double tempC() { // Convert the reading into degree Celsius return (((analogvalue() * 3.3) / 4095) - 0.5) * 100; } String message() { return "my name is particle"; } void setup() { Particle.variable("flag", flag); Particle.variable("analogvalue", analogvalue); Particle.variable("temp", tempC); Particle.variable("mess", message); pinMode(A0, INPUT); } void loop() { } It is also possible to pass a std::function, allowing the calculation function to be a method of a class: // CALCULATED FUNCTION IN CLASS EXAMPLE class MyClass { public: MyClass(); virtual ~MyClass(); void setup(); String calculateCounter(); protected: int counter = 0; }; MyClass::MyClass() { } MyClass::~MyClass() { } void MyClass::setup() { Particle.variable("counter", [this](){ return this->calculateCounter(); }); } String MyClass::calculateCounter() { return String::format("counter retrieved %d times", ++counter); } MyClass myClass; void setup() { myClass.setup(); } void loop() { } Each variable retrieval uses one Data Operation from your monthly or yearly quota. Setting the variable does not use Data Operations. Particle.function()Expose a function through the Cloud so that it can be called with POST /v1/devices/{DEVICE_ID}/{FUNCTION}. Particle.function allows code on the device to be run when requested from the cloud API. You typically do this when you want to control something on your device, say a LCD display or a buzzer, or control features in your firmware from the cloud. // SYNTAX bool success = Particle.function("funcKey", funcName); // Cloud functions must return int and take one String int funcName(String extra) { return 0; } Each function call request and response uses one Data Operation from your monthly or yearly quota. Setting up function calls does not use Data Operations. Up to 15 cloud functions may be registered and each function name is limited to a maximum of 12 characters (prior to 0.8.0), 64 characters (since 0.8.0). Note: Only use letters, numbers, underscores and dashes in function names. Spaces and special characters may be escaped by different tools and libraries causing unexpected results. A function callback procedure needs to return as quickly as possible otherwise the cloud call will timeout. The callback function is called application loop thread
context, between calls to loop(), during Particle.process(), and delay(). In order to register a cloud function, the user provides the funcKey, which is the string name used to make a POST request and a funcName, which is the actual name of the function that gets called in your app. The cloud function has to return an integer; -1 is commonly used for a failed function call. A cloud function is set up to take one argument of the String datatype. The argument has a maximum size of 64 to 1024 bytes of UTF-8 characters; see API Field Limits as the limit varies depending on Device OS version and sometimes the device. Functions can only be triggered using the Particle API, or tools that use the API, like the console, CLI, and mobile apps. It's not possible to directly call a function from another device, even on the same account. Publish and subscribe can be used if you need device-to-device communication. For non-product devices, only the account that has claimed the device can call a function on it. For product devices, if the device is claimed, the device owner's account can call a function on it. Additionally, the product owner can call a function whether the device is claimed or not. When using the default AUTOMATIC system mode, the cloud functions must be registered in the setup() function. The information about registered functions will be sent to the cloud when the setup() function has finished its execution. In the SEMI_AUTOMATIC and MANUAL system modes, the functions must be registered before Particle.connect() is called. Before 1.5.0: Variable and function registrations are only sent up once, about 30 seconds after connecting to the cloud. When using the AUTOMATIC system mode, make sure you register your cloud functions as early as possible in the setup() function, before you do any lengthy operations, delays, or things like waiting for a key press. Calling Particle.function() after the registration information has been sent does not re-send the request and the function will not work. // EXAMPLE USAGE int brewCoffee(String command); void setup() { // register the cloud function Particle.function("brew", brewCoffee); } void loop() { // this loops forever } // this function automagically gets called upon a matching POST request int brewCoffee(String command) { // look for the matching argument "coffee" counter); } void setup() { pinMode(D7, OUTPUT); } void loop() { if (needConnection()) { if
(!Particle.connected()) Particle.connect(); doConnectedWork(); } else { if (Particle.connected()) Particle.disconnect(); doOfflineWork(); } } Since 2.0.0: When disconnecting from the Cloud, by default, the system does not wait for any pending messages, such as cloud events, to be actually sent to acknowledged by the Cloud. This behavior can be changed either globally via Particle.setDisconnectOptions() or by passing an options object to Particle.disconnect(). The timeout parameter controls how long the system can wait for the pending messages to be acknowledged by the Cloud. // EXAMPLE - disconnecting from the Cloud gracefully
Particle.disconnect(CloudDisconnectOptions().graceful(true).timeout(5000)); // EXAMPLE - using chrono literals to specify a timeout Particle.disconnect(CloudDisconnectOptions().graceful(true).timeout(5s)); Note that the actual disconnection happens asynchronously. If necessary, waitUntil(Particle.disconnected) can be used to wait until the device has disconnected from the Cloud. While this function will disconnect from the Cloud, it will keep the connection to the network. If you would like to completely deactivate the network module, use WiFi.off() or Cellular.off() as appropriate. *NOTE: When the device is disconnected, many features are not possible, including over-the-air updates, reading Particle.variables, and calling Particle.functions. If you disconnect from the Cloud, you will NOT BE ABLE to flash new firmware over the air. Safe mode can be used to reconnect to the cloud. When your device connects to the Particle cloud, if often can do so by resuming the previous session. This dramatically reduces the amount of data used, from around 5-6 Kbytes of data for a full handshake to hundreds of bytes of data for a resume. While a full session handshake does not use data operations, if done excessively it can impact the total data usage on cellular devices. Sessions are automatically renegotiated every 3 days for security reasons. Under normal circumstances you will never have to manually invalidate the current session. However, if you have a need to do so, this is the best way: auto opts = CloudDisconnectOptions().clearSession(true); Particle.disconnect(opts); You may see references to spark/device/session/end in the community forums, however that method should not be used and may be deprecated in the future. The clearSession flag should be used instead. Particle.connected()Returns true when connected to the Cloud, and false when disconnected from the Cloud. // SYNTAX Particle.connected(); // EXAMPLE USAGE SerialLogHandler logHandler; void setup() { } void loop() { if (Particle.connected()) { Log.info("Connected!"); } delay(1000); } This call is fast and can be called frequently without performance degradation. Particle.disconnected()Returns true when disconnected from the Cloud, and false when connected to Cloud. Particle.setDisconnectOptions()Since 2.0.0: // EXAMPLE Particle.setDisconnectOptions(CloudDisconnectOptions().graceful(true).timeout(5000)); // EXAMPLE
Particle.setDisconnectOptions(CloudDisconnectOptions().graceful(true).timeout(5s)); Sets the options for when disconnecting from the cloud, such as from Particle.disconnect(). The default is to abruptly disconnect, however, you can use graceful disconnect mode to make sure pending events have been sent and the cloud notified that a disconnect is about to occur. Since this could take some time if there is poor cellular connectivity, a timeout can also be provided in milliseconds or using chrono literals. This setting will be used for future disconnects until the system is reset. Note: This method sets the disconnection options globally, meaning that any method that causes the device to disconnect from the Cloud, such as System.reset(), will do so gracefully. Particle.keepAlive()On all Gen 3 devices (Argon, Boron, B Series SoM, Tracker) and Gen 2 cellular devices: Sets the duration between keep-alive messages used to maintain the connection to the cloud. // SYNTAX Particle.keepAlive(23 * 60); // send a ping every 23 minutes A keep-alive is used to implement "UDP hole punching" which helps maintain the connection from the cloud to the device. A temporary port-forwarded back-channel is set up by the network to allow packets to be sent from the cloud to the device. As this is a finite resource, unused back-channels are periodically deleted by the network. Should a device becomes unreachable from the cloud (such as a timed out function call or variable get), one possible cause of this is that the keep alives have not been sent often enough. The keep-alive for cellular devices duration varies by mobile network operator. The default keep-alive is set to 23 minutes, which is sufficient to maintain the connection on Particle SIM cards. 3rd party SIM cards will need to determine the appropriate keep alive value, typically ranging from 30 seconds to several minutes. Note: Each keep alive ping consumes 122 bytes of data (61 bytes sent, 61 bytes received). For Ethernet, you will probably want to set a keepAlive of 2 to 5 minutes. For the Argon, the keep-alive is not generally needed. However, in unusual networking situations if the network router/firewall removes the port forwarded back-channels unusually aggressively, you may need to use a keep-alive. Keep-alives do not use Data Operations from your monthly or yearly quota. However, for cellular devices they do use cellular data, so setting it to a very small value can cause increased data usage, which could result in hitting the monthly data limit for your account. Since 1.5.0: You can also specify a value using chrono literals, for example: Particle.keepAlive(2min) for 2 minutes. Particle.process() Using SYSTEM_THREAD(ENABLED) is recommended for most applications. When using threading mode you generally do not need to use Particle.process(). If you are using SYSTEM_MODE(AUTOMATIC) (the default if you do not specify), or SEMI_AUTOMATIC you generally do not need to Particle.process() unless your code blocks and prevents loop from returning and does not use delay() in any inner blocking loop. In other words, if you block loop() from returning you must call either delay() or Particle.process() within your blocking inner loop. If you are using SYSTEM_MODE(MANUAL) you must call Particle.process() frequently, preferably on any call to loop() as well as any locations where you are blocking within loop(). Particle.process() checks the for incoming messages from the Cloud, and processes any messages that have come in. It also sends keep-alive pings to the Cloud, so if it's not called frequently, the connection to the Cloud may be lost. Particle.syncTime()Synchronize the time with the Particle Device Cloud. This happens automatically when the device connects to the Cloud. However, if your device runs continuously for a long time, you may want to synchronize once per day or so. #define ONE_DAY_MILLIS (24 * 60 * 60 * 1000) unsigned long lastSync = millis(); void loop() { if (millis() - lastSync > ONE_DAY_MILLIS) { // Request time synchronization from the Particle Device Cloud Particle.syncTime(); lastSync = millis(); } } Note that this function sends a request message to the Cloud and then returns. The time on the device will not be synchronized until some milliseconds later when the Cloud responds with the current time between calls to your loop. See Particle.syncTimeDone(), Particle.timeSyncedLast(), Time.isValid() and Particle.syncTimePending() for information on how to wait for request to be finished. Synchronizing time does not consume Data Operations from your monthly or yearly quota. However, for cellular devices they do use cellular data, so unnecessary time synchronization can lead to increased data usage, which could result in hitting the monthly data limit for your account. For more information about real-time clocks on Particle devices, see Learn more about real-time clocks. Particle.syncTimeDone()Since 0.6.1: Returns true if there is no syncTime() request currently pending or there is no active connection to Particle Device Cloud. Returns false when there is a pending syncTime() request. // SYNTAX Particle.syncTimeDone(); // EXAMPLE SerialLogHandler logHandler; void loop() { // Request time synchronization from the Particle Device Cloud Particle.syncTime(); // Wait until the device receives time from Particle Device Cloud (or connection to Particle Device Cloud is lost) waitUntil(Particle.syncTimeDone); // Print current time Log.info("Current time: %s", Time.timeStr().c_str()); } See also Particle.timeSyncedLast() and Time.isValid().
Particle.syncTimePending()Since 0.6.1: Returns true if there a syncTime() request currently pending. Returns false when there is no syncTime() request pending or there is no active connection to Particle Device Cloud. // SYNTAX Particle.syncTimePending(); // EXAMPLE SerialLogHandler logHandler; void loop() { // Request time synchronization from the Particle Device Cloud Particle.syncTime(); // Wait until the device receives time from Particle Device Cloud (or connection to Particle Device Cloud is lost) while(Particle.syncTimePending()) { // // Do something else // Particle.process(); } // Print current time Log.info("Current time: %s", Time.timeStr().c_str()); } See also Particle.timeSyncedLast() and Time.isValid(). Particle.timeSyncedLast()// EXAMPLE SerialLogHandler logHandler; #define ONE_DAY_MILLIS (24 * 60 * 60 * 1000) void loop() { time_t lastSyncTimestamp; unsigned long lastSync = Particle.timeSyncedLast(lastSyncTimestamp); if (millis() - lastSync > ONE_DAY_MILLIS) { unsigned long cur = millis(); Log.info("Time was last synchronized %lu milliseconds ago", millis() - lastSync); if (lastSyncTimestamp > 0) { Log.info("Time received from Particle Device Cloud was: ", Time.timeStr(lastSyncTimestamp).c_str()); } // Request time synchronization from Particle Device Cloud Particle.syncTime(); // Wait until the device receives time from Particle Device Cloud (or connection to Particle Device Cloud is lost) waitUntil(Particle.syncTimeDone); // Check if synchronized successfully if (Particle.timeSyncedLast() >= cur) { // Print current time Log.info("Current time: %s", Time.timeStr().c_str()); } } } Since 0.6.1: Used to check when time was last synchronized with Particle Device Cloud. // SYNTAX Particle.timeSyncedLast(); Particle.timeSyncedLast(timestamp); Returns the number of milliseconds since the device began running the current program when last time synchronization with Particle Device Cloud was performed. This function takes one optional argument: timestamp: time_t variable that will contain a UNIX timestamp received from Particle Device Cloud during last time synchronization It is possible that the call will block for an indeterminate amount of time, possibly for as long as 10 minutes. This can occur if the system thread is busy trying to reconnect to cellular and is unable to do so. Doing operations that access the cellular modem or require access to the system thread (as is the case for
Particle.timeSyncedLast()) from a separate worker thread is a good workaround. Get Public IPUsing this feature, the device can programmatically know its own public IP address. SYSTEM_THREAD(ENABLED); SerialLogHandler logHandler; bool nameRequested = false; // Open a serial terminal and see the IP address printed out void
subscriptionHandler(const char *topic, const char *data) { Log.info("topic=%s data=%s", topic, data); } void setup() { Particle.subscribe("particle/device/ip", subscriptionHandler); } void loop() { if (Particle.connected() && !nameRequested) { nameRequested = true; Particle.publish("particle/device/ip"); } } Note: Calling Particle Get Device nameThis gives you the device name that is stored in the cloud. SYSTEM_THREAD(ENABLED); SerialLogHandler logHandler; bool nameRequested = false; // Open a serial terminal and see the IP address printed out void subscriptionHandler(const char *topic, const char *data) { Log.info("topic=%s data=%s", topic, data); } void setup() {
Particle.subscribe("particle/device/name", subscriptionHandler); } void loop() { if (Particle.connected() && !nameRequested) { nameRequested = true; Particle.publish("particle/device/name"); } } Instead of fetching the name from the cloud each time, you can fetch it and store it in retained memory or EEPROM. The DeviceNameHelperRK library makes this easy. The link includes instructions and the library is available in Particle Workbench by using Particle: Install Library or in the Web IDE by searching for DeviceNameHelperRK. Get Random seedGrab 40 bytes of randomness from the cloud and {e}n{c}r{y}p{t} away! LogHandler logHandler; void handler(const char *topic, const char
*data) { Log.info("topic=%s data=%s", topic, data); } void setup() { Serial.begin(115200); Particle.subscribe("particle/device/random", handler); Particle.publish("particle/device/random"); } EthernetGen 3 Devices: Ethernet is available on the Argon, Boron when used with the Ethernet FeatherWing or with the B Series SoM with the evaluation board or the equivalent circuitry on your base board. It is not available on Gen 2 devices (Photon, P1, Electron, and E Series). By default, Ethernet detection is not done because it will toggle GPIO that may affect circuits that are not using Ethernet. When you select Ethernet during mobile app setup, it is enabled and the setting stored in configuration flash. It's also possible to enable Ethernet detection from code. This is saved in configuration flash so you don't need to call it every time. You should call it from setup() but make sure you are using SYSTEM_THREAD(ENABLED) so it can be enabled before the connecting to the cloud. You should not call it from STARTUP(). SYSTEM_THREAD(ENABLED); void setup() { System.enableFeature(FEATURE_ETHERNET_DETECTION); } If you are using the Adafruit Ethernet Feather Wing (instead of the Particle Feather Wing), be sure to connect the nRESET and nINTERRUPT pins (on the small header on the short side) to pins D3 and D4 with jumper wires. These are required for proper operation. When using the FeatherWing Gen 3 devices (Argon, Boron, Xenon), pins D3, D4, and D5 are reserved for Ethernet control pins (reset, interrupt, and chip select). When using Ethernet with the Boron SoM, pins A7, D22, and D8 are reserved for the Ethernet control pins (reset, interrupt, and chip select). on()Ethernet.on() turns on the Ethernet module. Useful when you've turned it off, and you changed your mind. Note that Ethernet.on() does not need to be called unless you have changed the system mode or you have previously turned the Ethernet module off. off()Ethernet.off() turns off the Ethernet module. connect()Attempts to connect to the Ethernet network. If there are no credentials stored, this will enter listening mode. When this function returns, the device may not have an IP address on the LAN; use Ethernet.ready() to determine the connection status. // SYNTAX Ethernet.connect(); disconnect()Disconnects from the Ethernet network, but leaves the Ethernet module on. // SYNTAX Ethernet.disconnect(); connecting()This function will return true once the device is attempting to connect using stored credentials, and will return false once the device has successfully connected to the Ethernet network. // SYNTAX Ethernet.connecting(); ready()This function will return true once the device is connected to the network and has been assigned an IP address, which means that it's ready to open TCP sockets and send UDP datagrams. Otherwise it will return false. // SYNTAX Ethernet.ready(); listen()This will enter or exit listening mode, which opens a Serial connection to get Ethernet credentials over USB, and also listens for credentials over Bluetooth. // SYNTAX - enter listening mode Ethernet.listen(); Listening mode blocks application code. Advanced cases that use multithreading, interrupts, or system events have the ability to continue to execute application code while in listening mode, and may wish to then exit listening mode, such as after a timeout. Listening mode is stopped using this syntax: // SYNTAX - exit listening mode Ethernet.listen(false); listening()// SYNTAX
Ethernet.listening(); Returns true if the device is in listening mode (blinking dark blue). This is only relevant when using SYSTEM_THREAD(ENABLED). When not using threading, listening mode stops user firmware from running, so you would not have an opportunity to test the value and calling this always returns false. setListenTimeout()// SYNTAX Ethernet.setListenTimeout(seconds); Ethernet.setListenTimeout(seconds) is used to set a timeout value for Listening Mode. Values are specified in seconds, and 0 disables the timeout. By default, Ethernet devices do not have any timeout set (seconds=0). As long as interrupts are enabled, a timer is started and running while the device is in listening mode (Ethernet.listening()==true). After the timer expires, listening mode will be exited automatically. If Ethernet.setListenTimeout() is called while the timer is currently in progress, the timer will be updated and restarted with the new value (e.g. updating from 10 seconds to 30 seconds, or 10 seconds to 0 seconds (disabled)).Note: Enabling multi- threaded mode with SYSTEM_THREAD(ENABLED) will allow user code to update the timeout value while Listening Mode is active. Since 1.5.0: You can also specify a value using chrono literals, for example: Ethernet.setListenTimeout(5min) for 5 minutes. getListenTimeout()// SYNTAX uint16_t seconds = Ethernet.getListenTimeout();
Ethernet.getListenTimeout() is used to get the timeout value currently set for Listening Mode. Values are returned in (uint16_t)seconds, and 0 indicates the timeout is disabled. By default, Ethernet devices do not have any timeout set (seconds=0). macAddress()Ethernet.macAddress() gets the MAC address of the Ethernet interface. // EXAMPLE SerialLogHandler logHandler; void setup() { // Wait for a USB serial connection for up to 30 seconds waitFor(Serial.isConnected, 30000); uint8_t addr[6]; Ethernet.macAddress(addr); Log.info("mac: %02x-%02x-%02x-%02x-%02x-%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); } localIP()Ethernet.localIP() is used to get the IP address of the Ethernet interface as an IPAddress. // EXAMPLE SerialLogHandler logHandler; void setup() { // Wait for a USB serial connection for up to 30 seconds waitFor(Serial.isConnected, 30000); Log.info("localIP: %s", Ethernet.localIP().toString().c_str()); } Ethernet.subnetMask() returns the subnet mask of the network as an IPAddress. SerialLogHandler logHandler; void setup() { // Wait for a USB serial connection for up to 30 seconds waitFor(Serial.isConnected, 30000); // Prints out the subnet mask over Serial. Log.info(Ethernet.subnetMask()); } gatewayIP()Ethernet.gatewayIP() returns the gateway IP address of the network as an IPAddress. SerialLogHandler logHandler; void setup() {
Serial.begin(9600); // Wait for a USB serial connection for up to 30 seconds waitFor(Serial.isConnected, 30000); // Prints out the gateway IP over Serial. Log.info(Ethernet.gatewayIP()); } dnsServerIP()Ethernet.dnsServerIP() retrieves the IP address of the DNS server that resolves DNS requests for the device's network connection. This will often be 0.0.0.0. dhcpServerIP()Ethernet.dhcpServerIP() retrieves the IP address of the DHCP server that manages the IP address used by the device's network connection. This often will be 0.0.0.0. WiFiWi-Fi Devices: The WiFi class is available on the Argon (Gen 3), Photon, and P1 (Gen 2). The WiFi class is not available on cellular devices such as the Boron and B Series SoM (Gen 3) or Electron and E Series (Gen 2). While the Tracker SoM has a Wi-Fi module for geolocation, it cannot be used for network connectivity and thus it does not have the WiFi class. on()WiFi.on() turns on the Wi-Fi module. Useful when you've turned it off, and you changed your mind. Note that WiFi.on() does not need to be called unless you have changed the system mode or you have previously turned the Wi-Fi module off. off()// EXAMPLE: Particle.disconnect(); WiFi.off(); WiFi.off() turns off the Wi-Fi module. Useful for saving power, since most of the power draw of the device is the Wi-Fi module. You must call Particle.disconnect() before turning off the Wi-Fi manually, otherwise the cloud connection may turn it back on again. This should only be used with SYSTEM_MODE(SEMI_AUTOMATIC) (or MANUAL) as the cloud connection and Wi-Fi are managed by Device OS in AUTOMATIC mode. connect()Attempts to connect to the Wi-Fi network. If there are no credentials stored, this will enter listening mode (see below for how to avoid this.). If there are credentials stored, this will try the available credentials until connection is successful. When this function returns, the device may not have an IP address on the LAN; use WiFi.ready() to determine the connection status. // SYNTAX WiFi.connect(); Since 0.4.5: It's possible to call WiFi.connect() without entering listening mode in the case where no credentials are stored: // SYNTAX WiFi.connect(WIFI_CONNECT_SKIP_LISTEN); If there are no credentials then the call does nothing other than turn on the Wi-Fi module. On Gen 3 devices (Argon, Boron, B Series SoM, and Tracker), prior to Device OS 2.0.0, you needed to call WiFi.on() or Cellular.on() before calling Particle.connect(). This is not necessary on Gen 2 devices (any Device OS version) or with 2.0.0 and later. disconnect()Disconnects from the Wi-Fi network, but leaves the Wi-Fi module on. // SYNTAX WiFi.disconnect(); connecting()This function will return true once the device is attempting to connect using stored Wi-Fi credentials, and will return false once the device has successfully connected to the Wi-Fi network. // SYNTAX WiFi.connecting(); ready()This function will return true once the device is connected to the network and has been assigned an IP address, which means that it's ready to open TCP sockets and send UDP datagrams. Otherwise it will return false. // SYNTAX WiFi.ready(); selectAntenna() [Antenna]Note: On the Photon and P1 (Gen 2), selectAntenna selects which antenna the device should connect to Wi-Fi with and remembers that setting until it is changed. Resetting Wi-Fi credentials does not clear the antenna setting. The Argon (Gen 3) does not have an antenna switch; it can only use an external
antenna. // SYNTAX STARTUP(WiFi.selectAntenna(ANT_INTERNAL)); // selects the CHIP antenna STARTUP(WiFi.selectAntenna(ANT_EXTERNAL)); // selects the u.FL antenna STARTUP(WiFi.selectAntenna(ANT_AUTO)); // continually switches at high speed between antennas WiFi.selectAntenna() selects one of three antenna modes on your Photon or P1. It takes one argument: ANT_AUTO, ANT_INTERNAL or ANT_EXTERNAL. WiFi.selectAntenna() must be used inside another function like STARTUP(), setup(), or loop() to compile. You may specify in code which antenna to use as the default at boot time using the STARTUP() macro. Note that the antenna selection is remembered even after power off or when entering safe mode. This is to allow your device to be configured once and then continue to function with the selected antenna when applications are flashed that don't specify which antenna to use. This ensures that devices which must use the external antenna continue to use the external antenna in all cases even when the application code isn't being executed (e.g. safe mode.) If no antenna has been previously selected, the ANT_INTERNAL antenna will be chosen by default. WiFi.selectAntenna() returns 0 on success, or -1005 if the antenna choice was not found. Other errors that may appear will all be negative values. // Use the STARTUP() macro to set the default antenna // to use system boot time. // In this case it would be set to the chip antenna STARTUP(WiFi.selectAntenna(ANT_INTERNAL)); void setup() { // your setup code } void loop() { // your loop code } listen()This will enter or exit listening mode, which opens a Serial connection to get Wi-Fi credentials over USB, and also listens for credentials over Soft AP on the Photon or BLE on the Argon. // SYNTAX - enter listening mode WiFi.listen(); Listening mode blocks application code. Advanced cases that use multithreading, interrupts, or system events have the ability to continue to execute application code while in listening mode, and may wish to then exit listening mode, such as after a timeout. Listening mode is stopped using this syntax: // SYNTAX - exit listening mode WiFi.listen(false); listening()// SYNTAX WiFi.listening(); Returns true if the device is in listening mode (blinking dark blue). This is only relevant when using SYSTEM_THREAD(ENABLED). When not using threading, listening mode stops user firmware from running, so you would not have an opportunity to test the value and calling this always returns false. setListenTimeout()Since 0.6.1: // SYNTAX WiFi.setListenTimeout(seconds); WiFi.setListenTimeout(seconds) is used to set a timeout value for Listening Mode. Values are specified in seconds, and 0 disables the timeout. By default, Wi-Fi devices do not have any timeout set (seconds=0). As long as interrupts are enabled, a timer is started and running while the device is in listening mode (WiFi.listening()==true). After the timer expires, listening mode will be exited automatically. If WiFi.setListenTimeout() is called while the timer is currently in progress, the timer will be updated and restarted with the new value (e.g. updating from 10 seconds to 30 seconds, or 10 seconds to 0 seconds (disabled)). Note: Enabling multi-threaded mode with SYSTEM_THREAD(ENABLED) will allow user code to update the timeout value while Listening Mode is active. // EXAMPLE // If desired, use the STARTUP() macro to set the timeout value at boot time. STARTUP(WiFi.setListenTimeout(60)); // set listening mode timeout to 60 seconds void setup() { // your setup code } void loop() { // update the timeout later in code based on an expression if (disableTimeout) WiFi.setListenTimeout(0); // disables the listening mode timeout } Since 1.5.0: You can also specify a value using chrono literals, for example: WiFi.setListenTimeout(5min) for 5 minutes. getListenTimeout()Since 0.6.1: // SYNTAX uint16_t seconds = WiFi.getListenTimeout(); WiFi.getListenTimeout() is used to get the timeout value currently set for Listening Mode. Values are returned in (uint16_t)seconds, and 0 indicates the timeout is disabled. By default, Wi-Fi devices do not have any timeout set (seconds=0).
setCredentials()Allows the application to set credentials for the Wi-Fi network from within the code. These credentials will be added to the device's memory, and the device will automatically attempt to connect to this network in the future. The Photon and P1 remember the 5 most recently set credentials. The Photon and P1 can store one set of WPA Enterprise credentials in Device OS 0.7.0 and later. The Argon remembers the 10 most recently set credentials. The Argon does not support WPA Enterprise. // Connects to an unsecured network. WiFi.setCredentials(ssid); WiFi.setCredentials("My_Router_Is_Big"); // Connects to a network secured with WPA2 credentials. WiFi.setCredentials(ssid, password); WiFi.setCredentials("My_Router", "mypasswordishuge"); // Connects to a network with a specified authentication procedure. // Options are WPA2, WPA, or WEP. WiFi.setCredentials(ssid, password, auth); WiFi.setCredentials("My_Router", "wepistheworst", WEP); When used with hidden or offline networks, the security cipher is also required. // for hidden and offline networks on the Photon, the security cipher is also needed // Cipher options are WLAN_CIPHER_AES, WLAN_CIPHER_TKIP and WLAN_CIPHER_AES_TKIP WiFi.setCredentials(ssid, password, auth, cipher); WiFi.setCredentials("SSID", "PASSWORD", WPA2, WLAN_CIPHER_AES); // Connects to a network with an authentication procedure specified by WiFiCredentials object WiFi.setCredentials(credentials); WiFiCredentials credentials; credentials.setSsid("My_Router") .setSecurity(WEP) .setPassword("wepistheworst"); WiFi.setCredentials(credentials); The password is limited to 64 7-bit ASCII characters. If you pass in a longer password, only the first 64 characters will be saved. Since 0.7.0: Note: WPA Enterprise is only supported on the Photon and P1 (Gen 2). It is not supported on the Argon (Gen 3). Credentials can be set using WiFiCredentials class. For information on setting up WPA2 Enterprise from the Particle CLI, see this article. // WPA2 Enterprise with EAP-TLS // We are setting WPA2 Enterprise credentials WiFiCredentials credentials("My_Enterprise_AP", WPA2_ENTERPRISE); // EAP type: EAP-TLS credentials.setEapType(WLAN_EAP_TYPE_TLS); // Client certificate in PEM format credentials.setClientCertificate("---BEGIN CERTIFICATE---\r" \ /* ... */ \ "---END CERTIFICATE---\r\r" ); // Private key in PEM format
credentials.setPrivateKey("---BEGIN RSA PRIVATE KEY---\r" \ /* ... */ \ "---END RSA PRIVATE KEY---\r\r" ); // Root (CA) certificate in PEM format (optional) credentials.setRootCertificate("---BEGIN CERTIFICATE---\r" \ /* ... */ \ "---END CERTIFICATE---\r\r" ); // EAP outer identity (optional, default - "anonymous")
credentials.setOuterIdentity("anonymous"); // Save credentials WiFi.setCredentials(credentials); // WPA Enterprise with PEAP/MSCHAPv2 // We are setting WPA Enterprise credentials WiFiCredentials credentials("My_Enterprise_AP", WPA_ENTERPRISE); // EAP type: PEAP/MSCHAPv2 credentials.setEapType(WLAN_EAP_TYPE_PEAP); // Set
username credentials.setIdentity("username"); // Set password credentials.setPassword("password"); // Set outer identity (optional, default - "anonymous") credentials.setOuterIdentity("anonymous"); // Root (CA) certificate in PEM format (optional) credentials.setRootCertificate("---BEGIN CERTIFICATE---\r" \ /* ... */ \ "---END CERTIFICATE---\r\r" ); // Save credentials WiFi.setCredentials(credentials); Parameters: This function returns true if credentials were successfully saved, or false in case of an error. Note: Setting WPA/WPA2 Enterprise credentials requires use of WiFiCredentials class. Note: In order for WiFi.setCredentials() to work, the Wi-Fi module needs to be on (if switched off or disabled via non_AUTOMATIC SYSTEM_MODEs call WiFi.on()). getCredentials()Since 0.4.9: Lists the Wi-Fi networks with credentials stored on the device. Returns the number of stored networks. Note that this returns details about the Wi-Fi networks, but not the actual password. // DEFINITION typedef struct WiFiAccessPoint { size_t size; char ssid[33]; uint8_t ssidLength; uint8_t bssid[6]; WLanSecurityType security; WLanSecurityCipher cipher; uint8_t channel; int maxDataRate; int rssi; } WiFiAccessPoint; // EXAMPLE LogHandler logHandler; WiFiAccessPoint ap[5]; int found = WiFi.getCredentials(ap, 5); for (int i = 0; i < found; i++) { Log.info("ssid: %s", ap[i].ssid); // security is one of WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA, WLAN_SEC_WPA2, WLAN_SEC_WPA_ENTERPRISE, WLAN_SEC_WPA2_ENTERPRISE Log.info("security: %d", (int) ap[i].security); // cipher is one of WLAN_CIPHER_AES, WLAN_CIPHER_TKIP or WLAN_CIPHER_AES_TKIP Log.info("cipher: %d", (int) ap[i].cipher); } This will clear all saved credentials from the Wi-Fi module's memory. This will return true on success and false if the Wi-Fi module has an error. // SYNTAX WiFi.clearCredentials(); hasCredentials()Will return true if there are Wi-Fi credentials stored in the Wi-Fi module's memory. // SYNTAX WiFi.hasCredentials(); macAddress()WiFi.macAddress() returns the MAC address of the device. // EXAMPLE USAGE SerialLogHandler logHandler; byte mac[6]; void setup() { WiFi.on(); // wait up to 10 seconds for USB host to connect // requires firmware >= 0.5.3 waitFor(Serial.isConnected, 10000); WiFi.macAddress(mac); Log.info("mac: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } SSID()WiFi.SSID() returns the SSID of the network the device is currently connected to as a char*. BSSID()WiFi.BSSID() retrieves the 6-byte MAC address of the access point the device is currently connected to. SerialLogHandler logHandler; byte bssid[6]; void setup() { Serial.begin(9600); // Wait for a USB serial connection for up to 30 seconds waitFor(Serial.isConnected, 30000); WiFi.BSSID(bssid); Log.info("%02X:%02X:%02X:%02X:%02X:%02X", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); } WiFi.RSSI() returns the signal strength of a Wi-Fi network from -127 (weak) to -1dB (strong) as an int. Positive return values indicate an error with 1 indicating a Wi-Fi chip error and 2 indicating a time-out error. // SYNTAX int rssi = WiFi.RSSI(); WiFiSignal rssi = WiFi.RSSI(); Since 0.8.0 WiFi.RSSI() returns an instance of WiFiSignal class. // SYNTAX WiFiSignal sig = WiFi.RSSI(); If you are passing the RSSI value as a variable argument, such as with Serial.printlnf, Log.info, snprintf, etc. make sure you add a cast:
Log.info("RSSI=%d", (int8_t) WiFi.RSSI()). This is necessary for the compiler to correctly convert the WiFiSignal class into a number. WiFiSignal ClassThis class allows to query a number of signal parameters of the currently connected WiFi network. getStrength()Gets the signal strength as a percentage (0.0 - 100.0). See getStrengthValue() on how strength values are mapped to 0%-100% range. // SYNTAX WiFiSignal sig = WiFi.RSSI(); float strength = sig.getStrength(); // EXAMPLE WiFiSignal sig = WiFi.RSSI(); Log.info("WiFi signal strength: %.02f%%", sig.getStrength()); Returns: float getQuality()Gets the signal quality as a percentage (0.0 - 100.0). See getQualityValue() on how quality values are mapped to 0%-100% range. // SYNTAX WiFiSignal sig = WiFi.RSSI(); float quality = sig.getQuality(); // EXAMPLE WiFiSignal sig = WiFi.RSSI(); Log.info("WiFi signal quality: %.02f%%", sig.getQuality()); Returns: float getStrengthValue()// SYNTAX WiFiSignal sig = WiFi.RSSI(); float strength = sig.getStrengthValue(); Gets the raw signal strength value in dBm. Range: [-90, 0]. Returns: float getQualityValue()// SYNTAX WiFiSignal sig = WiFi.RSSI(); float quality = sig.getQualityValue(); Gets the raw signal quality value (SNR) in dB. Range: [0, 90]. Returns: float ping()WiFi.ping() allows you to ping an IP address and returns the number of packets received as an int. It takes two forms: WiFi.ping(IPAddress remoteIP) takes an IPAddress and pings that address. WiFi.ping(IPAddress remoteIP, uint8_t nTries) and pings that address a specified number of times. Gen 3 Devices: WiFi.ping() is not available on Gen 3 Wi-Fi devices (Argon). scan()Returns information about access points within range of the device. The first form is the simplest, but also least flexible. You provide a array of WiFiAccessPoint instances, and the call to WiFi.scan() fills out the array. If there are more APs detected than will fit in the array, they are dropped. Returns the number of access points written to the array. // EXAMPLE - retrieve up to 20 Wi-Fi APs SerialLogHandler logHandler; WiFiAccessPoint aps[20]; int found = WiFi.scan(aps, 20); for (int i=0; inext(*wap); } // determine if this AP is stronger than the strongest seen so far void next(WiFiAccessPoint& ap) { if ((ap.rssi < 0) && (ap.rssi > strongest_rssi)) { strongest_rssi = ap.rssi; strcpy(strongest_ssid, ap.ssid); } } public: /** * Scan Wi-Fi Access Points and retrieve the strongest one. */ const char* scan() { // initialize data strongest_rssi = -128; strongest_ssid[0] = 0; // perform the scan WiFi.scan(handle_ap, this); return strongest_ssid; } }; // Now use the class FindStrongestSSID strongestFinder; const char* ssid = strongestFinder.scan(); } resolve()WiFi.resolve() finds the IP address for a domain name. // SYNTAX ip = WiFi.resolve(name); Parameters: name: the domain name to resolve (string) It returns the IP address if the domain name is found, otherwise a blank IP address. // EXAMPLE USAGE IPAddress ip; void setup() { ip = WiFi.resolve("www.google.com"); if(ip) { // IP address was resolved } else { // name resolution failed } } localIP()WiFi.localIP() returns the local IP address assigned to the device as an IPAddress. SerialLogHandler logHandler; void setup() { // Wait for a USB serial connection for up to 30 seconds waitFor(Serial.isConnected, 30000); // Prints out the local IP over Serial. Log.info("ip address: %s", WiFi.localIP().toString().c_str()); } WiFi.subnetMask() returns the subnet mask of the network as an IPAddress. SerialLogHandler logHandler; void setup() { // Wait for a USB serial connection for up to 30 seconds waitFor(Serial.isConnected, 30000); // Prints out the subnet mask over Serial. Log.info("subnet mask: %s" WiFi.subnetMask().toString().c_str()); } gatewayIP()WiFi.gatewayIP() returns the gateway IP address of the network as an IPAddress.
SerialLogHandler logHandler; void setup() { // Wait for a USB serial connection for up to 30 seconds waitFor(Serial.isConnected, 30000); // Prints out the gateway IP over Serial. Log.info("gateway: %s", WiFi.gatewayIP().toString().c_str()); } dnsServerIP()WiFi.dnsServerIP() retrieves the IP address of the DNS server that resolves DNS requests for the device's network connection. Note that for this value to be available requires calling Particle.process() after Wi-Fi has connected. dhcpServerIP()WiFi.dhcpServerIP() retrieves the IP address of the DHCP server that manages the IP address used by the device's network connection. Note that for this value to be available requires calling
Particle.process() after Wi-Fi has connected. setStaticIP()Defines the static IP addresses used by the system to connect to the network when static IP is activated. Static IP addressing is only available on the Photon and P1 (Gen 2). It is not available on the Argon or Ethernet (Gen 3). // SYNTAX void setup() { IPAddress myAddress(192,168,1,100); IPAddress netmask(255,255,255,0); IPAddress gateway(192,168,1,1); IPAddress dns(192,168,1,1); WiFi.setStaticIP(myAddress, netmask, gateway, dns); // now let's use the configured IP WiFi.useStaticIP(); } The addresses are stored persistently so that they are available in all subsequent application and also in safe mode. useStaticIP()Instructs the system to connect to the network using the IP addresses provided to WiFi.setStaticIP() The setting is persistent and is remembered until WiFi.useDynamicIP() is called. Static IP addressing is only available on the Photon and P1 (Gen 2). It is not available on the Argon or Ethernet (Gen 3). useDynamicIP()Instructs the system to connect to the network using a dynamically allocated IP address from the router. A note on switching between static and dynamic IP. If static IP addresses have been previously configured using WiFi.setStaticIP(), they continue to be remembered by the system after calling WiFi.useDynamicIP(), and so are available for use next time WiFi.useStaticIP() is called, without needing to be reconfigured using WiFi.setStaticIP() Static IP addressing is only available on the Photon and P1 (Gen 2). It is not available on the Argon or Ethernet (Gen 3). setHostname()Since 0.7.0: Sets a custom hostname to be used as DHCP client name (DHCP option 12). Parameters: hostname: the hostname to set (string) // SYNTAX
WiFi.setHostname("photon-123"); By default the device uses its device ID as hostname. The hostname is stored in persistent memory. In order to reset the hostname to its default value (device ID) setHostname() needs to be called with hostname argument set to NULL. // Reset hostname to default value (device ID) WiFi.setHostname(NULL); // Both these functions should return the same value. Serial.println(WiFi.getHostname()); Serial.println(System.deviceID()); Hostname setting is only available on the Photon and P1 (Gen 2). It is not available on the Argon or Ethernet (Gen 3). hostname()Since 0.7.0: Retrieves device hostname used as DHCP client name (DHCP option 12). This function does not take any arguments and returns a String. // SYNTAX String hostname = WiFi.hostname(); By default the device uses its device ID as hostname. See WiFi.setHostname() for documentation on changing the hostname. Hostname setting is only available on the Photon and P1 (Gen 2). It is not available on the Argon or Ethernet (Gen 3).
WiFiCredentials classThis class allows to define WiFi credentials that can be passed to WiFi.setCredentials() function. // EXAMPLE - defining and using WiFiCredentials class void setup() { // Ensure that WiFi module is on WiFi.on(); // Set up WPA2 access point "My AP" with password "mypassword" and AES cipher WiFiCredentials credentials("My AP", WPA2); credentials.setPassword("mypassword") .setCipher(WLAN_CIPHER_AES); // Connect if settings were successfully saved if (WiFi.setCredentials(credentials)) { WiFi.connect(); waitFor(WiFi.ready, 30000); Particle.connect(); waitFor(Particle.connected, 30000); } } void loop() { } WiFiCredentials()Constructs an instance of the
WiFiCredentials class. By default security type is initialized to unsecured (UNSEC). // SYNTAX WiFiCredentials credentials(SecurityType security = UNSEC); // 1 WiFiCredentials credentials(const char* ssid, SecurityType security = UNSEC); // 2 // EXAMPLE - constructing WiFiCredentials instance // Empty instance, security is set to UNSEC
WiFiCredentials credentials; // No SSID, security is set to WPA2 WiFiCredentials credentials(WPA2); // SSID set to "My AP", security is set to UNSEC WiFiCredentials credentials("My AP"); // SSID set to "My WPA AP", security is set to WPA WiFiCredentials credentials("My AP", WPA); Parameters: ssid: SSID (string) security: see SecurityType enum. setSsid()Sets access point SSID. // SYNTAX WiFiCredentials& WiFiCredentials::setSsid(const char* ssid); // EXAMPLE - setting ssid WiFiCredentials credentials; credentials.setSsid("My AP"); Parameters: setSecurity()Sets access point security type. // SYNTAX WiFiCredentials& WiFiCredentials::setSecurity(SecurityType security); // EXAMPLE - setting security type WiFiCredentials credentials; credentials.setSecurity(WPA2); Parameters: security: see SecurityType enum. setCipher()Sets access point cipher. // SYNTAX WiFiCredentials& WiFiCredentials::setCipher(WLanSecurityCipher cipher); // EXAMPLE - setting cipher WiFiCredentials credentials;
credentials.setCipher(WLAN_CIPHER_AES); Parameters: cipher: see WLanSecurityCipher enum. setPassword()Sets access point password. When configuring credentials for WPA/WPA2 Enterprise access point with PEAP/MSCHAPv2 authentication, this function sets password for username set by setIdentity(). // SYNTAX WiFiCredentials& WiFiCredentials::setPassword(const char* password); // EXAMPLE - setting password WiFiCredentials credentials("My AP", WPA2); credentials.setPassword("mypassword"); Parameters: password: WEP/WPA/WPA2 access point password, or user password for PEAP/MSCHAPv2 authentication (string) The password is limited to 64 7-bit ASCII characters. If you pass in a longer password, only the first 64 characters will be saved. setChannel()Sets access point channel. // SYNYAX WiFiCredentials& WiFiCredentials::setChannel(int channel); // EXAMPLE - setting channel WiFiCredentials credentials("My AP"); credentials.setChannel(10); Parameters: channel: WLAN channel (int)
setEapType()Sets EAP type. // SYNTAX WiFiCredentials& WiFiCredentials::setEapType(WLanEapType type); // EXAMPLE - setting EAP type WiFiCredentials credentials("My Enterprise AP", WPA2_ENTERPRISE); credentials.setEapType(WLAN_EAP_TYPE_PEAP); Parameters: type: EAP type. See WLanEapType enum for a list of supported values. This is a feature of WPA Enterprise and is only available on the Photon and P1 (Gen 2). It is not available on the Argon (Gen 3). setIdentity()Sets EAP inner identity (username in case of PEAP/MSCHAPv2). // SYNTAX WiFiCredentials& WiFiCredentials::setIdentity(const char* identity); // EXAMPLE - setting PEAP identity (username) WiFiCredentials
credentials("My Enterprise AP", WPA2_ENTERPRISE); credentials.setEapType(WLAN_EAP_TYPE_PEAP); credentials.setIdentity("username"); Parameters: identity: inner identity (string) setOuterIdentity()Sets EAP outer identity. Defaults to "anonymous". // SYNTAX WiFiCredentials& WiFiCredentials::setOuterIdentity(const char* identity); //
EXAMPLE - setting outer identity WiFiCredentials credentials("My Enterprise AP", WPA2_ENTERPRISE); credentials.setOuterIdentity("notanonymous"); Parameters: identity: outer identity (string) This is a feature of WPA Enterprise and is only available on the Photon and P1 (Gen 2). It is not available on the Argon (Gen 3). setClientCertificate()Sets client certificate used for EAP-TLS authentication. // SYNTAX WiFiCredentials& WiFiCredentials::setClientCertificate(const char* cert); // EXAMPLE - setting client certificate WiFiCredentials credentials; credentials.setClientCertificate("---BEGIN CERTIFICATE---\r" \ /* ... */ \ "---END CERTIFICATE---\r\r" ); Parameters: cert: client certificate in PEM format (string) This is a feature of WPA Enterprise and is only available on the Photon and P1 (Gen 2). It is not available on the Argon (Gen 3). setPrivateKey()Sets private key used for EAP-TLS authentication. // SYNTAX WiFiCredentials& WiFiCredentials::setPrivateKey(const char* key); // EXAMPLE - setting private key WiFiCredentials credentials; credentials.setPrivateKey("---BEGIN RSA PRIVATE KEY---\r" \ /* ... */ \ "---END RSA PRIVATE KEY---\r\r" ); Parameters: key: private key in PEM format (string) This is a feature of WPA Enterprise and is only available on the Photon and P1 (Gen 2). It is not available on the Argon (Gen 3). setRootCertificate()Sets one more root (CA) certificates. // SYNTAX WiFiCredentials& WiFiCredentials::setRootCertificate(const char* cert); // EXAMPLE - setting one root certificate WiFiCredentials credentials; credentials.setClientCertificate("---BEGIN CERTIFICATE---\r" \ /* ... */ \ "---END CERTIFICATE---\r\r" ); // EXAMPLE - setting multiple root certificates WiFiCredentials credentials; credentials.setClientCertificate("---BEGIN CERTIFICATE---\r" \ /* ... */ \ "---END CERTIFICATE---\r" "---BEGIN CERTIFICATE---\r" \ /* ... */ \ "---END CERTIFICATE---\r\r" ); Parameters: cert: one or multiple concatenated root certificates in PEM format (string) This is a feature of WPA Enterprise and is only available on the Photon and P1 (Gen 2). It is not available on the Argon (Gen 3). WLanEapType EnumThis enum defines EAP types. This is a feature of WPA Enterprise and is only available on the Photon and P1 (Gen 2). It is not available on the Argon (Gen 3). SecurityType EnumThis enum defines wireless security types. WLanSecurityCipher EnumThis enum defines wireless security ciphers. SoftAP HTTP PagesNote: SoftAP is available only on the Photon and P1 (Gen 2). It is not available on cellular devices or on the Argon (Gen 3 Wi-Fi). Since 0.5.0: When the device is in listening mode, it creates a temporary access point (AP) and a HTTP server on port 80. The HTTP server is used to configure the Wi-Fi access points the device attempts to connect to. As well as the system providing HTTP URLs, applications can add their own pages to the SoftAP HTTP server. SoftAP HTTP Pages is presently an advanced feature, requiring moderate C++ knowledge. To begin using the feature: add #include "Particle.h" below that, then add #include "softap_http.h" below that still // SYNTAX void myPages(const char* url, ResponseCallback* cb, void* cbArg, Reader* body, Writer* result, void* reserved); STARTUP(softap_set_application_page_handler(myPages, nullptr)); The softap_set_application_page_handler is set during startup. When the system is in setup mode (listening mode, blinking dark blue), and a request is made for an
unknown URL, the system calls the page handler function provided by the application (here, myPages.) The page handler function is called whenever an unknown URL is requested. It is called with these parameters: url: the path of the file requested by the client. It doesn't include the server name or port. Examples: /index, /someimage.jpg. cb: a response callback - this is used by the application to indicate the type of HTTP response, such as 200 (OK) or 404 (not found). More on this below. cbArg: data that should be passed as the first parameter to the callback function cb. body: a reader object that the page handler uses to retrieve the HTTP request body result: a writer object that the page handler uses to write the HTTP response body reserved: reserved for future expansion. Will be equal to nullptr and can be ignored. The application MUST call the page callback function cb to provide a response for the requested page. If the requested page url isn't recognized by the application, then a 404 response should be sent, as described below. The page callback functionWhen your page handler function is called, the system passes a result callback function as the cb parameter. The callback function takes these parameters: cbArg: this is the cbArg parameter passed to your page callback function. It's internal state used by the HTTP server. flags: presently unused. Set to 0. status: the HTTP status code, as an integer, such as 200 for OK, or 404 for page not found. mime-type: the mime-type of the response as a string, such as text/html or application/javascript. header: an optional pointer to a Header that is added to the response sent to the client. For example, to send a "not found" error for a page that is not recognized, your application code would call // EXAMPLE - send a 404 response for an unknown page cb(cbArg, 0, 404, "text/plain", nullptr); Retrieving the request dataWhen the HTTP request contains a request body (such as with a POST request), the Reader object provided by the body parameter can be used to retrieve the request data. // EXAMPLE if (body-
>bytes_left) { char* data = body->fetch_as_string(); // handle the body data dostuff(data); // free the data! IMPORTANT! free(data); } Sending a responseWhen sending a page, the page function responds with a HTTP 200 code, meaning the content was found, followed by the page data. // EXAMPLE - send a page if (!stricmp(url, '/helloworld') { // send the response code 200, the mime type "text/html" cb(cbArg, 0, 200, "text/html", nullptr); // send the page content result->write("hello world!"); } The default pageWhen a browser requests the default page ( the system internally redirects this to /index so that it can be handled by the application. The application may provide an actual page at /index or redirect to another page if the application prefers to have another page as its launch page. Sending a RedirectThe application can send a redirect response for a given page in order to manage the URL namespace, such as providing aliases for some resources. The code below sends a redirect from the default page /index to /index.html // EXAMPLE - redirect from /index to /index.html // add this code in the page hanler function if (strcmp(url,"/index")==0) { Header h("Location: /index.html\r"); cb(cbArg, 0, 301, "text/plain", &h); return; } Complete ExampleThe example source code can be downloaded here. Here's a complete example providing a Web UI for setting up WiFi via HTTP. Credit for the HTTP pages goes to GitHub user @mebrunet! (Included from PR #909 here) (Source code here) CellularCellular Devices: The Cellular class is available on the the Boron, B Series SoM, and Tracker (Gen 3) and Electron and E Series (Gen 2). It is not available on Wi-Fi devices including the Argon (Gen 3), Photon, and P1 (Gen 2). on()Cellular.on() turns on the Cellular module. Useful when you've turned it off, and you changed your mind. Note that Cellular.on() does not need to be called unless you have changed the system mode or you have previously turned the Cellular module off. When turning on the Cellular module, it will go through a full re-connect to the Cellular network which will take anywhere from 30 to 60 seconds in most situations. // SYNTAX Cellular.on(); Note: Cellular.on() API is non-blocking on all platforms except for Electron with threading disabled. Since 2.1.0: Cellular.isOn() can be used to actively wait for when the modem gets powered on. Alternatively network system events can be used to track the power state of the modem. off()Cellular.off() turns off the Cellular module. Useful for saving power, since most of the power draw of the device is the Cellular module. Note: turning off the Cellular module will force it to go through a full re-connect to the Cellular network the next time it is turned on. // SYNTAX Cellular.off(); // EXAMPLE Particle.disconnect();
Cellular.off(); You must not turn off and on cellular more than every 10 minutes (6 times per hour). Your SIM can be blocked by your mobile carrier for aggressive reconnection if you reconnect to cellular very frequently. If you are manually managing the cellular connection in case of connection failures, you should wait at least 5 minutes before stopping the connection attempt. When retrying on failure, you should implement a back-off scheme waiting 5 minutes, 10 minutes, 15 minutes, 20 minutes, 30 minutes, then 60 minutes between retries. Repeated failures to connect can also result in your SIM being blocked. You must call Particle.disconnect() before turning off the cellular modem manually, otherwise the cloud connection may turn the cellular modem back on. This should only be used with SYSTEM_MODE(SEMI_AUTOMATIC) (or MANUAL) as the cloud connection and cellular modem are managed by Device OS in AUTOMATIC mode. Note: Cellular.off() API is non-blocking on all platforms except for Electron with threading disabled. Since 2.1.0: Cellular.isOff() can be used to actively wait for when the modem gets powered off. Alternatively network system events can be used to track the power state of the modem. isOn()Since 2.1.0: This function will return true if the cellular modem is powered on and went through low level initialization. Otherwise it will return false. // SYNTAX Cellular.isOn(); // EXAMPLE Cellular.on(); waitFor(Cellular.isOn, 30000); isOff()Since 2.1.0: This function will return true if the cellular modem is powered off. Otherwise it will return false. // SYNTAX Cellular.isOff(); // EXAMPLE Cellular.off(); waitFor(Cellular.isOff, 60000); connect()Attempts to connect to the Cellular network. If there are no credentials entered, the default Particle APN for Particle SIM cards will be used. If no SIM card is inserted, the device will enter listening mode. If a 3rd party APN is set, these credentials must match the inserted SIM card for the device to connect to the cellular network. When this function returns, the device may not have a local (private) IP