Connecting the Electron 3G over TCP to Your own Server with third party SIM to send SD card data

Hello All.
I am working on an environment monitoring project in Uganda in which we are recording data from a wireless sensor network. The sink node captures the data and saves it to an SD card. It is a very low power operation (Transmitter nodes ~ 45μW, Sink node ~ 30mW). To reduce the power consumed by the uplink, we only switch it on after a custom time, say 1 hour, to upload data and switch it off again. The server receives the data via TCP (you have to write your own TCP listener. We have written one in C#). One challenge was the modem to use. We tried the SIM5320E with a some luck, and frequent broken connections. Upon landing on the Electron 3G, there is no going back! The TCP connection is very reliable and the library is very easy to use. I was not interested in anything to do with the particle cloud, the data rates are very expensive for us. We just wanted to use our own SIM card and our own server. It appears many people have found a challenge here, as can be seen here and here.
We also needed an SD library as well. This SD library was just what we needed. Thanks to Bill Greiman.
I am just posting the code you need to do this, and I assume you have already done the hardware connections yourself.

#include "sdfat/SdFat.h"  /*the sdfat folder is in the project folder*/
SYSTEM_MODE(MANUAL); /*do not autoconnect to particle cloud*/
STARTUP(cellular_credentials_set("PUT_YOUR_APN_HERE", "", "", NULL));
/*my APN has no username and no password. adjust accordingly*/

// SPI configuration 0
// Primary SPI with DMA
// SCK => A3, MISO => A4, MOSI => A5, SS => A2 (default)
SdFat sd;
const uint8_t chipSelect = SS;

/*TCP configuration*/
TCPClient client;
String server = ""; /*your server IP address or domain name*/

File myFile;

void setup() {
/*uncomment line above to make program proceed after USART input*/

  while(!Cellular.ready()); //wait until condition is true
  Serial.println("connected to cellular network. ...");
  Serial.println("connecting to TCP...");
/*5000 is the port number on which the listener is awaiting data*/
  if (client.connect(server, 5000)) 
    Serial.println("connected to server");
  // Initialize SdFat or print a detailed error message and halt
  // Use half speed like the native library.
  // Change to SPI_FULL_SPEED for more performance.
  if (sd.begin(chipSelect, SPI_HALF_SPEED)) {
    Serial.println("SD opened successfully");
  } else     sd.initErrorHalt();

  // re-open the file for reading:
  if ("data.bin", O_READ)) {
      Serial.printf("File opened successfully. Size is %d\n", myFile.fileSize());
  } else   sd.errorHalt("opening for read failed");

  // read from the file until there's nothing else in it:
  int data,i=0;
  byte buff [1024];  /*see transmission metrics regarding choice of 1024*/
  while ((data = >= 0) {
      client.write(buff, i);
/*write remaining data. buff was partially filled before loop terminated*/
  client.write(buff, i);  
  Serial.printf("Remainder bytes were %d\n",i);
    // close the file:
  Serial.println("file closed. done.");
  Serial.println("Cellular link disconnected.");

void loop() {
  // nothing happens after setup

That’s it! Very Simple!
A few things to note:

  1. It matters what size of buffer you chose. A small buffer will make your transmissions slow. A very large buffer may not give much difference. I suspect it is because the LISA U260 on the Electron has a fixed-size hardware buffer. These were the transmission speeds over a 3G link. The 157KB file had 1000 lines of data, each about 150 bytes long. Buffer sizes larger than 1024 did not seem to improve the speed.
  2. The time to connect to a mobile service provider will vary with provider and with location. In my case, it was about 27-34 seconds.

Hope this helps some one out there!



What kind of sensor data are you capturing?

What kind of low power radios are you using?

We are measuring lots of stuff. Wind speed, direction, solar insolation, air temperature, humidity, soil moisture, soil temperature, precipitation and atmospheric pressure. The nodes are placed at various elevations above the ground.

We are using a custom designed node based on the ATMEGA256RFR2 and the Contiki embedded OS. Check it out at
The ATMEGA256RFR2 has a radio with a feature called Reduced Power Consumption for low power listening and the transmitter nodes are in sleep most of the time.

1 Like

This is really cool. I had no idea Electron could write to an SD card. :grin: What hardware did you use for the physical connection between SD card and Electron?

How do you control the transmission with electron? (I noticed there is no loop or sleep functions.) Is there an external timer powering on the electron and thus running the code above?

Really cool project. Thanks for sharing! :slight_smile:

I used a micro SD module from here. The image is below:

I forgot to mention how the electron is controlled. The sinknode is a wireless sensor node from Radio Sensors AB. It writes the received data to the SD card. The SD card is one slave serving 2 masters, the node and the Electron. Once a given time has elapsed, the node powers the Electron up through a transistor and stops writing or reading from the SD card so that the Electron can take over.

1 Like

@mbyamukama - it sounds like you have already solved everything but we support Electron over TCP with our local cloud fork -

You can use the SD Fat library to use SD cards with the Photon and Electron. Just started testing this myself and it works perfectly.

Do I understand correctly that you are effectively dual-porting the SD card between two processors? If so I would appreciate more details.

I am in the process of converting an existing system from Photon to Electron or E series. The application captures a 0.5 MByte file twice daily. The intent of using the Electron is to transmit metadata following each recording session without the need for the user to set up wifi credentials,. I then need to be able to recover the full data set once the device is returned to the lab. This is not feasible given the data rates charged by Particle/Telstra in Australia, There are third party suppliers that are feasible - this is an option with the Electron but not the E series.

I am exploring the option of using something like an ESP8266 or ESP32 to transmit the data over wifi once the device is back in the lab. Your solution of dual-porting an SD card sounds interesting. When it is time to extract the full files I could have the Electron trigger a web server on the ESP32 then get out of the way, allowing the ESP32 to serve files from the SD card. Sort of the reverse of your application.

I would appreciate your thoughts and experience.

Hi @OziGreybeard.
I should have given more details about that. Having 2 masters on 1 slave is actually proving to be unreliable. What we did was to disable the SPI interface of the sinknode. Sometimes, we just don’t read any data and the Electron reports an error at sdInitErrorHalt(). So we have since reverted to sending the data over the serial port. In one forum, I have been pointed to this document. (Our sinknode is an AVR microcontroller). The solution they mention is to free all the SPI lines of one master to be GPIO I/Os. I am giving this a shot this week because it would greatly simplify the task. I will post my luck as soon as it gets through.

From what I understand of your project and cost constraints, you might consider LoRaWAN for this use case. It operates in the ISM bands and should offer better range (900 MHz versus 2.4 GHz) and power consumption profile (assuming Class A will work for you). Fairly straightforward to setup a private network.

Thanks for the suggestion. Lorawan is not suited for the daily summary reports as there is no viable lore an net in Adelaide. Patients come from a wide area. It’s data rate is too slow for downloading the files in the lab.

LoRaWAN is not suitable for this use case. The total separation of the wireless nodes in this case is typically very small. Usually all nodes are within 10-20m of each other for Automatic Weather Stations and may be as much as 100m, depending on the transmission power and circumstances. All transmissions from the sensor nodes are typically downlink to the sink node, which has the one uplink to the server. You could have an uplink per sensor node but that brings in a power challenge, and power minimization is on top of our list right now.
I was happy to listen to a presentation on LoRaWAN in Cape Town in September, 2017 at the IEEE AFRICON conference. It’s possible application is in environment monitoring but the needs and requirements and implementation would be different.

Dear mbyamukama,

Can you share the TCP listener you wrote? I’m trying to do a similar project but I’m facing an issue regarding how to create the web server.

Thank you,

here you go. The executable file is larger with the Microsoft C# compiler than with Mono on Linux. If you are using a linux server, better to compile using mono on the server. the file size is smaller and stream write operations are just a little bit faster, but to no useful consequence. The listener receives data and writes to a text file. Another process sends the data to a relational database.

We did manage to implement the 2-master-1 slave design by using a normally closed quad single-pole single-throw analog switch (DG201BDJE3 -
In essence, this simply makes it a multi-tasked 1-master 1-slave. The Electron sets all the IN (switch control) lines high from one of its digital pins when it is powered up and causes the switch to isolate the 4 SPI lines from the other master.
We struggled with the on-resistance though. For a single supply, you have the SPI signals running through 90Ω before reaching the SD card. We think a better similar design is to use the ADG794 ( which instead has 4 2:1 multiplexers.

That said, we did not implement any of these designs. What we have now is the Electron in Deep Sleep, instead of being powered off. The sink node wakes it up though the D1 pin and then sends the data over the serial port. The Electron writes the data to the SD card itself and resumes the sleep state. It uploads the data after a given number of reports. Our opportunity cost is that we now have a 14.6mA system instead of a 13mA system. The extra 1.6mA from the Electron is little extra juice for significantly more uncomplicated design.

1 Like

@mbyamukama, if you are waking the Electron via D1 then it can’t be in deep sleep. You would need to wake via the WKP pin for that. Deep sleep would give you even lower power consumption.

Sorry, you’re right. We simply have it in sleep mode–since we need to preserve most of the RAM contents anyway, such as the report count, when we wake up. The line doing that looks like this:

1 Like

There is backup RAM which alliws to keep several KB of variables retained even after a reset.

@ScruffR, Thanks. Just read about it in the post by @rickkas7 here. Easy syntax as well.

Thanks. With imminent (July) release of the Xenon and Boron boards I am considering a different track myself. I have found a 3rd party provider with reasonable data allowances for my needs.

I am investigating using a Xenon to collect data at 250 Hz and transmit it to Boron as a recorder, analyser and gateway. This not only isolates the acquisition from timing glitches induced by recording to sd card (specifically flushing the buffer) and possibly the 3G/LTE link but would allow the sensor to be attached to the device with a BLE or Mesh link to the gateway/display.

Thanks for your update