Photon wi-fi signal strength indicator LED

There was recently a question about a wi-fi signal strength indicator on the Photon. I considered a few other things like a full RGB LED or a red-green-yellow 3-pin LED, but eventually decided on a plain LED. The brightness indicates the signal strength. Since it’s hard to determine how bright the LED is without something to compare it against, it flashes briefly at full brightness right before it checks, currently every 10 seconds, making comparison easy, and also providing a way to tell that it’s working.

I’m not sure of the use case of such a thing, but it’s kind of neat. Feel free to take the code and modify it to suit your needs.

Video:

Code:

#include "Particle.h"

// You pretty much need to use system thread enabled (or manual mode) because otherwise when you go out of range,
// loop stops running when the cloud connection is lost, and the LED won't update anymore. This isn't very helpful,
// but enabling the system thread will allow the LED to continue to update.
// https://docs.particle.io/reference/firmware/photon/#system-thread
SYSTEM_THREAD(ENABLED);

// Begin RSSIIndicator Class
// Include this class in your program. You'll probably create a global instantiation of the object, like:
// RSSIIndicator rssiIndicator(A5);
// Where A5 is the pin to use for output. See note below about which pins can be used; they must be PWM compatible.
//
// Also make sure you call the object's setup and loop methods out of your setup and loop.
class RSSIIndicator {
public:
	const unsigned long showFullBrightnessMs = 250;
	const unsigned long checkPeriodMs = 10000;
	enum RSSIIndicatorState { RSSIINDICATORSTATE_CHECK, RSSIINDICATORSTATE_WAIT, RSSIINDICATORSTATE_BRIGHT };

	RSSIIndicator(int pin);
	virtual ~RSSIIndicator();

	void setup();

	void loop();

private:
	int pin;
	enum RSSIIndicatorState state = RSSIINDICATORSTATE_CHECK;
	unsigned long stateTime = 0 - checkPeriodMs;
};

RSSIIndicator::RSSIIndicator(int pin) : pin(pin) {
}

RSSIIndicator::~RSSIIndicator() {
}

void RSSIIndicator::setup() {
	pinMode(pin, OUTPUT);
}

void RSSIIndicator::loop() {
	switch(state) {
	case RSSIINDICATORSTATE_CHECK:
		// This state checks the WiFi signal strength and sets the LED brightness appropriately
		stateTime = millis();
		state = RSSIINDICATORSTATE_WAIT;

		{
			// WiFi.RSSI() returns:
			// -127 (weak) to -1dB (strong)
			// or positive values for error codes
			// In practice, I've found that I never get close to -127 before losing the connection
			// so I adjusted this so -85 = min, -1 = max
			int rssi = WiFi.RSSI();
			if (rssi < 0) {
				int value = (85 + rssi) * 3;
				if (value < 0) {
					value = 0;
				}
				if (value > 255) {
					value = 255;
				}
				analogWrite(pin, value);
			}
			else {
				// This case runs when WiFi is disconnected
				analogWrite(pin, 0);
			}
		}
		break;

	case RSSIINDICATORSTATE_WAIT:
		// This waits to amount of time between checks (default: 10 seconds)
		if (millis() - stateTime >= checkPeriodMs) {
			stateTime = millis();
			if (showFullBrightnessMs > 0) {
				state = RSSIINDICATORSTATE_BRIGHT;
				analogWrite(pin, 255);
			}
			else {
				// Set showFullBrightnessMs to 0 to not flash at full brightness before checking
				state = RSSIINDICATORSTATE_CHECK;
			}
		}
		break;

	case RSSIINDICATORSTATE_BRIGHT:
		// Since it's hard to judge how bright the LED is without something to compare it with, and
		// also to provide an indication that it's actually doing something, briefly flash the LED
		// at full brightness before checking signal strength again. The default is to do it for
		// 250 milliseconds, which seems about right to me.
		if (millis() - stateTime >= showFullBrightnessMs) {
			stateTime = millis();
			state = RSSIINDICATORSTATE_CHECK;
		}
		break;
	}
}

// End RSSIIndicator Class

// Create a global RSSIIndicator object and specify the pin the LED is connected to.
// Only PWM compatible pins may be used:
// On the Photon and Electron, this function works on pins D0, D1, D2, D3, A4, A5, WKP, RX and TX with a caveat:
// PWM timer peripheral is duplicated on two pins (A5/D2) and (A4/D3) for 7 total independent PWM outputs.
// For example: PWM may be used on A5 while D2 is used as a GPIO, or D2 as a PWM while A5 is used as an analog input.
// However A5 and D2 cannot be used as independently controlled PWM outputs at the same time.
// https://docs.particle.io/reference/firmware/photon/#analogwrite-pwm-
RSSIIndicator rssiIndicator(A5);

void setup() {
	// Make sure you call rssiIndicator.setup() out of setup!
	rssiIndicator.setup();
}

void loop() {
	// Make sure you call rssiIndicator.loop() out of loop. You could also use a software timer to do this, probably
	// 250 milliseconds (or whatever you've set as showFullBrightnessMs is probably good.
	rssiIndicator.loop();
}


6 Likes

I think the green/amber/red would be a much better implementation.

I don’t really care what the RSSI is. What I care about is which of these 3 states my device is in

  1. the wifi is strong and should not be a problem

  2. the wifi is sketchy, if you are having problems, it’s likely the wifi

  3. the wifi is too weak, don’t expect anything to work.

To me this is a great candidate for green/amber/red type feedback. I would want to measure what RSSI range corresponds to these 3 states, and program them to trigger accordingly. I guess it could be done with the single led as well and just make it flash once, twice, or 3 times.

I give this opinion while at the same time I’m very grateful for your generous contributions! :smile: I have many projects that are difficult to keep close to wifi (yes they should probably be electrons instead), so I spend lots of time doubting my wifi signal strength. Thanks!!

Without any extra hardware RGB.control(true) and RGB.color() would be an option too.

2 Likes

I like that idea. What are the RSSI values that you found that can indicate those states? Which RSSI level probably will mean a sketchy condition? And which will be too weak?

This is a different version of the code that blinks the D7 LED from 1 to 4 times depending on the Wi-Fi signal strength. I set the boundaries at -40, -60, and -80. You’ll probably want to fine-tune the values, but that’s a reasonable place to start.

#include "Particle.h"

// You pretty much need to use system thread enabled (or manual mode) because otherwise when you go out of range,
// loop stops running when the cloud connection is lost, and the LED won't update anymore. This isn't very helpful,
// but enabling the system thread will allow the LED to continue to update.
// https://docs.particle.io/reference/firmware/photon/#system-thread
SYSTEM_THREAD(ENABLED);
//SYSTEM_MODE(MANUAL);


// Begin RSSIIndicator Class
// Include this class in your program. You'll probably create a global instantiation of the object, like:
// RSSIIndicator rssiIndicator(D2, D3);
// Where D2 is the pin connected to the red anode of a red-green-yellow LED.
// and D3 is the pin connected to the green anode of a red-green yellow LED.
// Also make sure you call the object's setup and loop methods out of your setup and loop.
class RSSIIndicator {
public:
	// How often between checks of the wi-fi signal strength
	const unsigned long checkPeriodMs = 4000;

	const unsigned long blinkOnMs = 200;
	const unsigned long blinkOffMs = 200;

	enum RSSIIndicatorState { RSSIINDICATORSTATE_CHECK, RSSIINDICATORSTATE_ON, RSSIINDICATORSTATE_ON_WAIT, RSSIINDICATORSTATE_OFF_WAIT, RSSIINDICATORSTATE_CHECK_WAIT };

	RSSIIndicator(int pinR);
	virtual ~RSSIIndicator();

	void setup();

	void loop();

private:
	int pin;
	enum RSSIIndicatorState state = RSSIINDICATORSTATE_CHECK;
	int blinksLeft;
	unsigned long stateTime = 0 - checkPeriodMs;
};

RSSIIndicator::RSSIIndicator(int pin) : pin(pin){
}

RSSIIndicator::~RSSIIndicator() {
}

void RSSIIndicator::setup() {
	pinMode(pin, OUTPUT);
}

void RSSIIndicator::loop() {
	switch(state) {
	case RSSIINDICATORSTATE_CHECK:
		// This state checks the WiFi signal strength and sets the LED brightness appropriately
		stateTime = millis();
		state = RSSIINDICATORSTATE_ON;

		{
			// WiFi.RSSI() returns:
			// -127 (weak) to -1dB (strong)
			// or positive values for error codes
			// In practice, I've found that I never get close to -127 before losing the connection.
			// I somewhat arbitrarily selected the values below
			int rssi = WiFi.RSSI();
			if (rssi < 0) {
				if (rssi > -40) {
					blinksLeft = 4;
				}
				else
				if (rssi > -60) {
					blinksLeft = 3;
				}
				else
				if (rssi > -80) {
					blinksLeft = 2;
				}
				else {
					blinksLeft = 1;
				}
			}
			else {
				// This case runs when WiFi is disconnected
				blinksLeft = 1;
			}

		}
		// Fall through

	case RSSIINDICATORSTATE_ON:
		if (blinksLeft-- <= 0) {
			state = RSSIINDICATORSTATE_CHECK_WAIT;
			break;
		}
		digitalWrite(pin, HIGH);
		stateTime = millis();
		state = RSSIINDICATORSTATE_ON_WAIT;
		break;

	case RSSIINDICATORSTATE_ON_WAIT:
		if (millis() - stateTime >= blinkOnMs) {
			digitalWrite(pin, LOW);
			stateTime = millis();
			state = RSSIINDICATORSTATE_OFF_WAIT;
		}
		break;

	case RSSIINDICATORSTATE_OFF_WAIT:
		if (millis() - stateTime >= blinkOffMs) {
			stateTime = millis();
			state = RSSIINDICATORSTATE_ON;
		}
		break;

	case RSSIINDICATORSTATE_CHECK_WAIT:
		// This waits to amount of time between checks (default: 10 seconds)
		if (millis() - stateTime >= checkPeriodMs) {
			stateTime = millis();
			state = RSSIINDICATORSTATE_CHECK;
		}
		break;
	}
}

// End RSSIIndicator Class

// Create a global RSSIIndicator object and specify the pin the LEDs is connected to, such
// as D7 for the built-in blue LED next to D7.
RSSIIndicator rssiIndicator(D7);

void setup() {
	// Make sure you call rssiIndicator.setup() from setup!
	rssiIndicator.setup();
}

void loop() {
	rssiIndicator.loop();
}


3 Likes

Nice class template as well!

1 Like

This code is great @rickkas7. I added some text for serial monitor and colours as suggested by @vinistois and @ScruffR.

#include "Particle.h"

// You pretty much need to use system thread enabled (or manual mode) because otherwise when you go out of range,
// loop stops running when the cloud connection is lost, and the LED won't update anymore. This isn't very helpful,
// but enabling the system thread will allow the LED to continue to update.
// https://docs.particle.io/reference/firmware/photon/#system-thread
SYSTEM_THREAD(ENABLED);
//SYSTEM_MODE(MANUAL);


// Begin RSSIIndicator Class
// Include this class in your program. You'll probably create a global instantiation of the object, like:
// RSSIIndicator rssiIndicator(D2, D3);
// Where D2 is the pin connected to the red anode of a red-green-yellow LED.
// and D3 is the pin connected to the green anode of a red-green yellow LED.
// Also make sure you call the object's setup and loop methods out of your setup and loop.
class RSSIIndicator {
public:
	// How often between checks of the wi-fi signal strength
	const unsigned long checkPeriodMs = 4000;

	const unsigned long blinkOnMs = 200;
	const unsigned long blinkOffMs = 200;

	enum RSSIIndicatorState { RSSIINDICATORSTATE_CHECK, RSSIINDICATORSTATE_ON, RSSIINDICATORSTATE_ON_WAIT, RSSIINDICATORSTATE_OFF_WAIT, RSSIINDICATORSTATE_CHECK_WAIT };

	RSSIIndicator(int pinR);
	virtual ~RSSIIndicator();

	void setup();

	void loop();

private:
	int pin;
	enum RSSIIndicatorState state = RSSIINDICATORSTATE_CHECK;
	int blinksLeft;
	unsigned long stateTime = 0 - checkPeriodMs;
};

RSSIIndicator::RSSIIndicator(int pin) : pin(pin){
}

RSSIIndicator::~RSSIIndicator() {
}

void RSSIIndicator::setup() {
	pinMode(pin, OUTPUT);
}

void RSSIIndicator::loop() {
	switch(state) {
	case RSSIINDICATORSTATE_CHECK:
		// This state checks the WiFi signal strength and sets the LED brightness appropriately
		stateTime = millis();
		state = RSSIINDICATORSTATE_ON;

		{
			// WiFi.RSSI() returns:
			// -127 (weak) to -1dB (strong)
			// or positive values for error codes
			// In practice, I've found that I never get close to -127 before losing the connection.
			// I somewhat arbitrarily selected the values below
			int rssi = WiFi.RSSI();
			if (rssi < 0) {
				RGB.control(true);
				if (rssi > -40) {
					blinksLeft = 4;
					Serial.println("Signal strength is good! RSSI:"+String(rssi)+"dB.");
					//RGB.control(true);
					RGB.color(0, 255, 0);
				}
				else
				if (rssi > -60) {
					Serial.println("Signal strength is OK - RSSI:"+String(rssi)+"dB.");
					blinksLeft = 3;
					//RGB.control(true);
					RGB.color(128, 196, 0);
				}
				else
				if (rssi > -80) {
					Serial.println("Signal strength is problematic - RSSI:"+String(rssi)+"dB.");
					blinksLeft = 2;
					//RGB.control(true);
					RGB.color(255, 96, 0);
				}
				else {
					Serial.println("Signal strength is almost unusable - RSSI:"+String(rssi)+"dB.");
					blinksLeft = 1;
					//RGB.control(true);
					RGB.color(255, 0, 0);
				}
			}
			else {
				// This case runs when WiFi is disconnected
				RGB.color(10, 0, 0);
				blinksLeft = 1; Serial.println("Wifi is disconnected. RSSI:"+String(rssi)+"dB.");
			}
		
		}
		// Fall through

	case RSSIINDICATORSTATE_ON:
		if (blinksLeft-- <= 0) {
			state = RSSIINDICATORSTATE_CHECK_WAIT;
			break;
		}
		digitalWrite(pin, HIGH);
		stateTime = millis();
		state = RSSIINDICATORSTATE_ON_WAIT;
		break;

	case RSSIINDICATORSTATE_ON_WAIT:
		if (millis() - stateTime >= blinkOnMs) {
			digitalWrite(pin, LOW);
			stateTime = millis();
			state = RSSIINDICATORSTATE_OFF_WAIT;
		}
		break;

	case RSSIINDICATORSTATE_OFF_WAIT:
		if (millis() - stateTime >= blinkOffMs) {
			stateTime = millis();
			state = RSSIINDICATORSTATE_ON;
		}
		break;

	case RSSIINDICATORSTATE_CHECK_WAIT:
		// This waits to amount of time between checks (default: 10 seconds)
		if (millis() - stateTime >= checkPeriodMs) {
			stateTime = millis();
			state = RSSIINDICATORSTATE_CHECK;
		}
		break;
	}
}

// End RSSIIndicator Class

// Create a global RSSIIndicator object and specify the pin the LEDs is connected to, such
// as D7 for the built-in blue LED next to D7.
RSSIIndicator rssiIndicator(D7);

void setup() {
		RGB.control(true);
    Serial.begin(9600);
    Serial.println("This program reports WIFI RSSI (Received Signal Strength Indication");
    Serial.println("From 0dB (ideal) to -120dB (probably unusable)");


	// Make sure you call rssiIndicator.setup() from setup!
	rssiIndicator.setup();
}

void loop() {
	rssiIndicator.loop();
}
1 Like