Boron LTE 3rd Party SIM Issues

I’m trying to evaluate how viable the Boron LTE would be for my application. I use a decent amount of data, so a Particle SIM is a non-starter. The device can connect as normal with the internal SIM card.

When using an external, 3rd party, SIM, the device blinks green forever (rc27). My code calls the following:

if (Cellular.getActiveSim() != EXTERNAL_SIM) Cellular.setActiveSim(EXTERNAL_SIM);
Cellular.setCredentials("hologram");

I’ve tried power resets after setting credentials but still no dice.

I understand that the carrier needs to support LTE CAT M1. My cellular provider, Hologram gives me access to both Verizon and AT&T’s LTE CAT-M1 networks. Other people using the same SIM card have successfully connected at least to Verizon’s network. There is no apn difference for CAT M1.

Is there any way I can get more detailed debug information? The lack of Cellular.command() is definitely challenging here.

Also, has anyone successfully used the Boron LTE with a 3rd Party SIM? I couldn’t find any examples posted here yet of anyone who has.

EDIT: here’s the tinker serial debug output:

0000001743 [hal] TRACE: Modem powered off
0000001743 [hal] TRACE: Powering modem on
0000001894 [hal] TRACE: Modem powered on
0000001895 [hal] TRACE: Setting UART voltage translator state 1
0000002895 [ncp.at] TRACE: > AT
0000003895 [ncp.at] TRACE: > AT
0000004895 [ncp.at] TRACE: > AT
0000005895 [ncp.at] TRACE: > AT
0000006895 [ncp.at] TRACE: > AT
0000006898 [ncp.at] TRACE: < AT
0000006899 [ncp.at] TRACE: < OK
0000007899 [hal] TRACE: NCP ready to accept AT commands
0000007899 [ncp.at] TRACE: > AT+UGPIOC?
0000007903 [ncp.at] TRACE: < AT+UGPIOC?
0000007904 [ncp.at] TRACE: < +UGPIOC:
0000007905 [ncp.at] TRACE: < 16,255
0000007906 [ncp.at] TRACE: < 19,255
0000007906 [ncp.at] TRACE: < 23,0
0000007907 [ncp.at] TRACE: < 24,255
0000007907 [ncp.at] TRACE: < 25,255
0000007908 [ncp.at] TRACE: < 42,255
0000007909 [ncp.at] TRACE: < OK
0000007909 [ncp.at] TRACE: > AT+UGPIOR=23
0000007914 [ncp.at] TRACE: < AT+UGPIOR=23
0000007915 [ncp.at] TRACE: < +UGPIOR: 23,0
0000007916 [ncp.at] TRACE: < OK
0000007917 [hal] INFO: Using external Nano SIM card
0000007917 [ncp.at] TRACE: > AT+CPIN?
0000007921 [ncp.at] TRACE: < AT+CPIN?
0000007922 [ncp.at] TRACE: < +CPIN: READY
0000007923 [ncp.at] TRACE: < OK
0000007923 [ncp.at] TRACE: > AT+CCID
0000007927 [ncp.at] TRACE: < AT+CCID
0000007929 [ncp.at] TRACE: < +CCID: 8944502311176184336
0000007930 [ncp.at] TRACE: < OK
0000007931 [ncp.at] TRACE: > AT+COPS=2
0000007935 [ncp.at] TRACE: < AT+COPS=2
0000007941 [ncp.at] TRACE: < OK
0000007942 [ncp.at] TRACE: > AT+CEDRXS=0
0000007946 [ncp.at] TRACE: < AT+CEDRXS=0
0000007946 [ncp.at] TRACE: < OK
0000007947 [ncp.at] TRACE: > AT+CPSMS=0
0000007951 [ncp.at] TRACE: < AT+CPSMS=0
0000007952 [ncp.at] TRACE: < OK
0000007952 [ncp.at] TRACE: > AT+CEDRXS?
0000007957 [ncp.at] TRACE: < AT+CEDRXS?
0000007958 [ncp.at] TRACE: < +CEDRXS: 2,"1001"
0000007960 [ncp.at] TRACE: < +CEDRXS: 5,"1001"
0000007961 [ncp.at] TRACE: < OK
0000007961 [ncp.at] TRACE: > AT+CPSMS?
0000007964 [ncp.at] TRACE: < AT+CPSMS?
0000007976 [ncp.at] TRACE: < +CPSMS:0,,,"01100000","00000000"
0000007977 [ncp.at] TRACE: < OK
0000007978 [ncp.at] TRACE: > AT+CMUX=0,0,,1509,,,,,
0000007986 [ncp.at] TRACE: < AT+CMUX=0,0,,1509,,,,,
0000007987 [ncp.at] TRACE: < OK
0000007988 [gsm0710muxer] INFO: Starting GSM07.10 muxer
0000007989 [gsm0710muxer] INFO: Openning mux channel 0
0000007990 [gsm0710muxer] INFO: GSM07.10 muxer thread started
0000008041 [gsm0710muxer] INFO: Resuming channel 0
0000008041 [gsm0710muxer] INFO: Openning mux channel 1
0000008142 [gsm0710muxer] INFO: Resuming channel 1
0000008142 [gsm0710muxer] INFO: Resuming channel 1
0000008144 [ncp.at] TRACE: > AT
0000008194 [ncp.at] TRACE: < AT
0000008194 [ncp.at] TRACE: < OK
0000008195 [hal] TRACE: NCP state changed: 1
0000008195 [net.pppncp] TRACE: NCP event 1
0000008196 [hal] TRACE: Muxer AT channel live
0000008198 [hal] TRACE: PPP thread event LOWER_DOWN
0000008198 [hal] TRACE: PPP thread event ADM_DOWN
0000008200 [hal] TRACE: PPP thread event ADM_UP
0000008202 [hal] TRACE: State NONE -> READY
0000008201 [ncp.at] TRACE: > AT+CGDCONT=1,"IP","hologram"
0000008244 [ncp.at] TRACE: < AT+CGDCONT=1,"IP","hologram"
0000008245 [ncp.at] TRACE: < OK
0000008245 [ncp.at] TRACE: > AT+CEREG=2
0000008294 [ncp.at] TRACE: < AT+CEREG=2
0000008294 [ncp.at] TRACE: < OK
0000008295 [hal] TRACE: NCP connection state changed: 1
0000008295 [net.pppncp] TRACE: NCP event 2
0000008296 [net.pppncp] TRACE: State changed event: 1
0000008297 [ncp.at] TRACE: > AT+COPS=0
0000008298 [hal] TRACE: PPP thread event LOWER_DOWN
0000008344 [ncp.at] TRACE: < AT+COPS=0
0000008344 [ncp.at] TRACE: < OK
0000008345 [ncp.at] TRACE: > AT+CEREG?
0000008346 [ncp.at] TRACE: < +CEREG: 2
0000008394 [ncp.at] TRACE: < AT+CEREG?
0000008394 [ncp.at] TRACE: < +CEREG: 2,2
0000008395 [ncp.at] TRACE: < OK
0000023396 [ncp.at] TRACE: > AT+CEREG?
0000023444 [ncp.at] TRACE: < AT+CEREG?
0000023444 [ncp.at] TRACE: < +CEREG: 2,2
0000023445 [ncp.at] TRACE: < OK
0000038446 [ncp.at] TRACE: > AT+CEREG?
0000038494 [ncp.at] TRACE: < AT+CEREG?
0000038494 [ncp.at] TRACE: < +CEREG: 2,2
0000038495 [ncp.at] TRACE: < OK
0000053496 [ncp.at] TRACE: > AT+CEREG?
0000053544 [ncp.at] TRACE: < AT+CEREG?
0000053544 [ncp.at] TRACE: < +CEREG: 2,2
0000053545 [ncp.at] TRACE: < OK
0000060954 [sys.power] TRACE: re-enabling charging
0000060992 [sys.power] TRACE: Battery state DISCONNECTED -> CHARGED
0000062093 [sys.power] TRACE: Battery state CHARGED -> DISCONNECTED
0000068546 [ncp.at] TRACE: > AT+CEREG?
0000068595 [ncp.at] TRACE: < AT+CEREG?
0000068595 [ncp.at] TRACE: < +CEREG: 2,2
0000068596 [ncp.at] TRACE: < OK
1 Like

I tried to use the hologram sim on a Boron LTE, and just like you had the same result. I contacted support at hologram.io and they confirmed that their sim card is capable of connecting to both Verizon and AT&T LTE-Cat M1 networks. One of the devices they sell uses the exact same cellular module as Boron LTE. They however said that they didn’t test the boron lte on their network yet, but it’s planned.
Did you test with a sim card on the flexible data plan? I’m using a sim that’s still on one of their older free plan (pilot- 1MB) and was wondering if that’s the reason I can’t get it connected.

I use a special “All Carriers” high bandwidth plan for our company. It should be sufficient for access to Cat M1. It’s definitely possible that your plan could be part of your issue - make sure you are on one of the plans that isn’t T-Mobile only.

Edit: I’ve also reached out to my folks at Hologram about this btw, so I’ll be sure to update if they have any insights beyond what this community has.

2 Likes

Same / exact issue here!

Also:
My Hologram SIM works well on Arduino MKR 1400 (3G) and MKR NB 1500 (Cat M1, and same modem as Boron).
AT&T is what Hologram likes to connect to in my area.
Boron works well with built-in SIM.

Yet, despite following all directions (hybrid device firmware, updated credentials app, etc., directions here are clear), I cannot get past blinking green with Hologram SIM. Frustrating, especially with no cellular (AT) commands yet.

I have. I spent all day yesterday getting the Boron LTE I ordered last week to work with a data-only SIM from Google Fi.

It’s amazing to me how Particle has so much documentation, but it’s often next to impossible to find what one is looking for…

The Boron would not set up properly, as my Argon did without any issue, using the Particle Android app. It would scan the QR code, connect, download the firmware update, then asked if I wanted to use it in a mesh network or not. I did not, but regardless of which I chose, I received a modal alert to add a credit card using the Billing section of the Console with OK/Exit Setup options to tap. Have no idea why that happened - I bought the product understanding I’d get 3 months of data on Particle for free, though my intent was to use a 3rd party SIM as soon as possible. I attempted the setup process again maybe 8 times, also used a different phone - no dice. I emailed support and haven’t heard back. Super annoying.

I decided to work through the “Using a 3rd Party Sim” instructions found here:

https://docs.particle.io/support/particle-devices-faq/electron-3rdparty-sims/

This was tedious, to say the least. Since the app didn’t recognize and let me claim my Boron, I had to flash this locally (something I would love for uploading regular code, easily, a la Arduino, but alas…). Flashing the device requires persistence, as it does not work successfully about 50% of the time. Just keep trying.

The same goes for getting simple info like the ICCID with “particle identify” using the CLI - it just displayed the device ID, not the ICCID. Oh, then it did. Then it didn’t. Then it did again.

Ditto for manually claiming the device or renaming it from the CLI. Didn’t work. Didn’t work. Didn’t work.
Worked.

I removed it from the USB port on my MacBook and plugged it into the wall with a USB charger and it flashed green for about 10 minutes. Unplugged/plugged and it did the same thing. Unplugged/plugged, made a gin and tonic, came back a few minutes later and I had “breathing cyan” we all long for. It showed up in Console. I pinged it.

I tried to flash the simple Blink LED with a keepAlive() function call in the setup: it said it was taking a while to connect to my device, found it, was flashing it, then flash status failed. I did this maybe a dozen times with the same result. Not useful when you can’t get your code to the device.

Walked to work this morning, put it on the window sill of my office and plugged it in. Flashing green for 5 minutes.

Unplugged/plugged, flashing green for 5 minutes.

Unplugged/plugged, flashing green with a sporadic trio of orange flashes. At least it was something different. Seeing different colors renewed my optimism. Apparently, this means it’s connected to the network (T-Mobile), but can’t phone home to Particle because of “bad server keys.”

Unplugged/plugged, flashing green, then breathing cyan. Immediately opened the web IDE and flashed my Blink/keepAlive app and it updated. The LED blinked and it successfully sent packets every 2 minutes.

Six hours later to the minute it disconnected and has been flashing green for half an hour.

So, yes, it worked. Briefly. It might work again. It might not. I don’t have these troubles with my Adafruit Feather, NodeMCU, and Arduino MKR WiFI 1010 devices. Granted, they’re not cellular - but as attractive as the Particle stuff is, I won’t be fooling with it in the future. Too frustrating. I’ll give the MKR GSM 1440 or Adafruit FONA a shot instead. My Argon will find some love eventually.

I hope you have better luck!

While it’s difficult to set up a Boron LTE with a 3rd-party SIM card, at least in the United States it should be possible to use Google Fi. It should work with a Boron 2G/3G in most locations.

This binary can be flashed in --usb mode to a Boron LTE (0.8.0-rc.27 or later recommended). It took a while to make the first connection, but once it did it worked fine. It’s a modified version of Tinker so you can control it from the CLI, console, or mobile app to make sure it’s communicating successfully.

#include "Particle.h"

#include "dct.h"

SYSTEM_MODE(SEMI_AUTOMATIC);

SerialLogHandler logHandler(LOG_LEVEL_ALL);

/* Function prototypes -------------------------------------------------------*/
int tinkerDigitalRead(String pin);
int tinkerDigitalWrite(String command);
int tinkerAnalogRead(String pin);
int tinkerAnalogWrite(String command);

/* This function is called once at start up ----------------------------------*/
void setup()
{
	//Setup the Tinker application here
	Cellular.setActiveSim(EXTERNAL_SIM);
	Cellular.setCredentials("h2g2");

	// This clears the setup done flag on brand new devices so it won't stay in listening mode
	const uint8_t val = 0x01;
	dct_write_app_data(&val, DCT_SETUP_DONE_OFFSET, 1);

	//Register all the Tinker functions
	Particle.function("digitalread", tinkerDigitalRead);
	Particle.function("digitalwrite", tinkerDigitalWrite);

	Particle.function("analogread", tinkerAnalogRead);
	Particle.function("analogwrite", tinkerAnalogWrite);

	Particle.keepAlive(30);
	Particle.connect();
}

/* This function loops forever --------------------------------------------*/
void loop()
{
	//This will run in a loop
}

/*******************************************************************************
 * Function Name  : tinkerDigitalRead
 * Description    : Reads the digital value of a given pin
 * Input          : Pin
 * Output         : None.
 * Return         : Value of the pin (0 or 1) in INT type
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerDigitalRead(String pin)
{
	//convert ASCII to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber < 0 || pinNumber > 7) return -1;

	if(pin.startsWith("D"))
	{
		pinMode(pinNumber, INPUT_PULLDOWN);
		return digitalRead(pinNumber);
	}
	else if (pin.startsWith("A"))
	{
		pinMode(pinNumber+10, INPUT_PULLDOWN);
		return digitalRead(pinNumber+10);
	}
#if Wiring_Cellular
	else if (pin.startsWith("B"))
	{
		if (pinNumber > 5) return -3;
		pinMode(pinNumber+24, INPUT_PULLDOWN);
		return digitalRead(pinNumber+24);
	}
	else if (pin.startsWith("C"))
	{
		if (pinNumber > 5) return -4;
		pinMode(pinNumber+30, INPUT_PULLDOWN);
		return digitalRead(pinNumber+30);
	}
#endif
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerDigitalWrite
 * Description    : Sets the specified pin HIGH or LOW
 * Input          : Pin and value
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerDigitalWrite(String command)
{
	bool value = 0;
	//convert ASCII to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber < 0 || pinNumber > 7) return -1;

	if(command.substring(3,7) == "HIGH") value = 1;
	else if(command.substring(3,6) == "LOW") value = 0;
	else return -2;

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		digitalWrite(pinNumber, value);
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		digitalWrite(pinNumber+10, value);
		return 1;
	}
#if Wiring_Cellular
	else if(command.startsWith("B"))
	{
		if (pinNumber > 5) return -4;
		pinMode(pinNumber+24, OUTPUT);
		digitalWrite(pinNumber+24, value);
		return 1;
	}
	else if(command.startsWith("C"))
	{
		if (pinNumber > 5) return -5;
		pinMode(pinNumber+30, OUTPUT);
		digitalWrite(pinNumber+30, value);
		return 1;
	}
#endif
else return -3;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogRead
 * Description    : Reads the analog value of a pin
 * Input          : Pin
 * Output         : None.
 * Return         : Returns the analog value in INT type (0 to 4095)
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerAnalogRead(String pin)
{
	//convert ASCII to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber < 0 || pinNumber > 7) return -1;

	if(pin.startsWith("D"))
	{
		return -3;
	}
	else if (pin.startsWith("A"))
	{
		return analogRead(pinNumber+10);
	}
#if Wiring_Cellular
	else if (pin.startsWith("B"))
	{
		if (pinNumber < 2 || pinNumber > 5) return -3;
		return analogRead(pinNumber+24);
	}
#endif
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogWrite
 * Description    : Writes an analog value (PWM) to the specified pin
 * Input          : Pin and Value (0 to 255)
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerAnalogWrite(String command)
{
	String value = command.substring(3);

	if(command.substring(0,2) == "TX")
	{
		pinMode(TX, OUTPUT);
		analogWrite(TX, value.toInt());
		return 1;
	}
	else if(command.substring(0,2) == "RX")
	{
		pinMode(RX, OUTPUT);
		analogWrite(RX, value.toInt());
		return 1;
	}

	//convert ASCII to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits

	if (pinNumber < 0 || pinNumber > 7) return -1;

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		analogWrite(pinNumber, value.toInt());
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		analogWrite(pinNumber+10, value.toInt());
		return 1;
	}
	else if(command.substring(0,2) == "TX")
	{
		pinMode(TX, OUTPUT);
		analogWrite(TX, value.toInt());
		return 1;
	}
	else if(command.substring(0,2) == "RX")
	{
		pinMode(RX, OUTPUT);
		analogWrite(RX, value.toInt());
		return 1;
	}
#if Wiring_Cellular
	else if (command.startsWith("B"))
	{
		if (pinNumber > 3) return -3;
		pinMode(pinNumber+24, OUTPUT);
		analogWrite(pinNumber+24, value.toInt());
		return 1;
	}
	else if (command.startsWith("C"))
	{
		if (pinNumber < 4 || pinNumber > 5) return -4;
		pinMode(pinNumber+30, OUTPUT);
		analogWrite(pinNumber+30, value.toInt());
		return 1;
	}
#endif
else return -2;
}
2 Likes

Thanks for this - will give it a try later this week!