Using a camera and sending JPEG to cloud

Hi,
I am looking at doing something like the CCTV camera project show on the kickstarter site.
I have looked at the camera https://www.sparkfun.com/products/11610 and the demo code.
My query is how to transmit the JPEG picture, the example code on the sparkfun site re transmits the JPEG data over the serial port.
How would I deal with this data? does the spark have enough memory to store the JPEG? Can I use one GET to retrieve the whole image?
Any clues / pointers or example code would help

Thanks

4 Likes

The Core has something like 10K of memory free for you to use (out of the 20K SRAM on the chip). You should probably work with the JPEG in chunks using your own buffer of, say, 1024 bytes. You could connect to your own server with TCPClient and send the file over that connection.

We definitely have this use case on our radar, but I just added a task to our backlog to post an annotated example of sending an image using TCPClient. Until then, check out the TCPClient docs here: http://docs.spark.io/#/firmware/communication-tcpclient

Let us know how it goes!

1 Like

I think I’ll take a crack at this over the next few days. I’m working with the 4D uCam and its library (which will need some adapting from Due to Spark).

I hate to be a pain, but I’m not totally sure how to send chunked data over TCPClient so I’d like to ask for a bit of clarification. I’m comfortable writing a web-side POST form to receive data, it’s just the Arduino I’m not so sure of…

To send an image, would one just get data in chunks inside the if (client.connect(server, 80)){} loop and keep printing to serial?

It’s good practice to let loop() fall through quickly, so rather than sending the whole file in a single call of loop(), you should send the HTTP headers on the first loop, one chunk of the file per loop, then the last boundary and close the socket on a final loop.

You’ll need to read a chunk at a time from the camera over serial and send that chunk over TCP.

The format of a minimal HTTP POST file upload looks something like this once a TCP socket is open.

POST /pictures HTTP/1.1
Host: www.example.com
Content-Type: multipart/form-data; boundary=----somegibberish----
Content-Length: 9999

----somegibberish----
Content-Disposition: form-data; name="latest_image"; filename="img.jpg"
Content-Type: image/jpeg
Content-Transfer-Encoding: binary

...contents of the jpeg file...
----somegibberish----

The Content-Length header needs to actually list the length in bytes of the body, so you have to be able to calculate that up front. The body is the part after the headers and one blank line.

The real story: http://tools.ietf.org/html/rfc1867

Will this be Spark Cloud limitation which could not transmit large amount of data ?
So, it must use another server to perform this operation, correct ?

Right now there are 3 ways to transmit data via the Spark Cloud.

Spark.function allows you to send an ASCII text string up to 63 characters as an argument and return a 4-byte integer.

Spark.variable allows you to expose an INT, DOUBLE, or STRING on the Core via the Cloud. The maximum length of the string is 622 characters.

Spark.publish and Spark.subscribe allow you to send events with a data payload of up to 63 characters.

You can get very creative with these primitives. For example I’ve seen a solution for sending large text files that involved something like this:

  1. Device exposes a char[622] as a STRING Spark.variable.
  • Device exposes a nextChunk Spark.function that copies the next (up to) 622 characters into the Spark.variable and returns the number of characters copied
  • API client opens SSE stream to subscribe for “file-available” events
  • Device publishes a “file-available” event
  • API client calls the nextChunk function and saves the returned number of bytes X
  • API client gets the Spark.variable and reads X characters
  • Repeat steps 5 & 6 until nextChunk returns 0.

A simpler, but slower alternative would be to publish the large data in 63 byte chunks, every second, until the large file transfer is finished. A subscriber to an SSE stream via the Spark API could assemble such a file super easily, even in a browser.

That said though, building a process like this can seem cumbersome, which is why it’s often better for large file transfers to happen between the Core and your own server. Also, because a Spark.variable has to contain ASCII text (and is a C string terminated by any zero byte), if your data is binary, then you have to convert it to some other encoding like hex or base64. Because of the Core’s constrained memory, too, you always have to build some chunking mechanism, even when talking to your own server. :smiley:

Cheers!

1 Like

Also, @emc2, just wanted to mention that if on the server you can read plain socket data instead of accepting an HTTP POST, the firmware code will get a lot easier!

@zachary are you referring to the socket library mentioned at https://community.spark.io/t/websockets-client/3090/28 ? I am eventually thinking about a socket connection, but for a quick prototype just wanted to capture decent resolution images from a camera and transfer them to an endpoint without storage.

I’m not quite ready for a project share, but here’s a peek at the app in progress: https://ionic-basic-spark.herokuapp.com

Workflow:

  1. Accounts tab: add new account
  2. Cores tab: add new cores from account
  3. (Optional) Cores tab: select core, set a color and icon. Handy for visual ID later
  4. Listeners tab: add new listener. Uses JS SSE listeners, only the “Publish Event” listener type does anything. Enter details for a core that you know is broadcasting Spark.publish() events regularly.
  5. Dashboard: swipe left and right to move between event panels for each core

All data is kept as localstorage, so it never leaves your browser (except for the original account auth, which goes to API) - it’s safe to save data. No databases involved. Having images or heavier broadcast data in here would be awesome :slight_smile:

Looks great @emc2! Looking forward to that project share!

Nope, not WebSockets—I mean good old standard TCP sockets, which are what the firmware TCPClient creates and what HTTP runs on top of. HTTP is just a TCP socket, with specific agreed-upon text formatting going back and forth.

On heroku, I don’t think you can run a generic TCP server, but I could be wrong.

Here are 3 minimal example TCP socket servers that can handle multiple concurrent connections. The node and ruby examples are just based on the language docs. For python, I basically used one from a Stack Overflow post.


JavaScript

var net = require('net');

var server = new net.Server();
server.on('connection', function (socket) {
  socket.on('data', function (buffer) {
    console.log('received data:', buffer.toString());
    socket.write(buffer);
  });
});
server.listen(3000);

Ruby

require 'socket'

server = TCPServer.new 3000
loop do
  Thread.start(server.accept) do |client|
    loop do
      data = client.gets
      puts "received data: #{data}"
      client.puts data
    end
  end
end

Python

import socket, threading

class ClientThread(threading.Thread):
  def __init__(self, ip, port, socket):
    threading.Thread.__init__(self)
    self.ip, self.port, self.socket = ip, port, socket

  def run(self):
    data = "_"
    while len(data):
      data = clientsock.recv(1024)
      print "received data: " + data
      clientsock.sendall(data)

tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpsock.bind(("0.0.0.0", 3000))

threads = []

while True:
  tcpsock.listen(4)
  (clientsock, (ip, port)) = tcpsock.accept()
  newthread = ClientThread(ip, port, clientsock)
  newthread.start()
  threads.append(newthread)

for t in threads:
  t.join()