This is a follow-up post on how to build a water temperature sensor using the Arduino GSM shield and Xively. This post should make sense on its own, but if you want to read the first part you can find it here.

The biggest problem with the sensor we made in the first post is that it cannot operate on battery power for any considerable amount of time. In our testing using 8 AA-batteries the sensor lasted for about 24hrs, which is not acceptable for most sensors. So, how can we make it run for longer periods of time?

image

Power down the modem and LEDs

The first thing to do is to disconnect the GPRS connection and turn off the modem when it is not in use. The modem is the biggest energy consumer, reaching 2W in some configurations. So we need a way to switch it off and on again.

We start by making a function to turn on the modem, and set up the connection. This should seem familiar if you have read the previous post, as the code is more or less identical to its setup function. Whereas in the previous version of the program you might get away with not having a delay between connecting to GSM and setting up the GPRS connection, it becomes quite important here since we are disconnecting and connecting more than once. In our testing we usually had problems connecting to the network during rush-hour when using too small of a delay, so even if your code works right now, it might not tomorrow morning. We still had problems using 1s delay so we bumped it up to 3s and have not had any problems since. You might get away with a lower delay, but it should at least be 1s.

void startConnection(){
  while (notConnected) {
    digitalWrite(3,HIGH);
    if(gsmAccess.begin(PINNUMBER)==GSM_READY){
      delay(3000);
      if(gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD)==GPRS_READY){
        notConnected = false;
        digitalWrite(redLed, LOW);
        digitalWrite(greenLed, HIGH);
      }
    }
    else{
      digitalWrite(redLed, HIGH);
      delay(1000);
    }
  }
}

Then lets look at how to disconnect. The heart of this function is the call to the GSM shutdown() function. We use the notConnected boolean to check that we are connected, then try to shut down the modem. If it managed to shut down, we turn off all LEDs to save power while not connected.

void closeConnection(){
  while(notConnected==false){
    if(gsmAccess.shutdown()){
      delay(1000);
      digitalWrite(3,LOW);
      notConnected = true;
      digitalWrite(redLed, LOW);
      digitalWrite(greenLed, LOW);
    }
    else{
      delay(1000);
    }
  }
}

We now have a way of turning the modem off and on in between measurements. So in the loop function we start by calling startConnection(), measure temperature, upload the data, and end with calling closeConnection().

Set serial pins to low

Setting the serial RX pin on the GSM shield low after shutdown saved us a lot of energy. This seems to be a problem that is well known, and will be added in a future version of the library. In the meantime we need to do this ourselves.

Change GSM operating frequency

The Arduino GSM shield uses the Quectel M10 modem. This is a quad-band modem, meaning it can run on all four most common GSM frequencies. The modems specifications tells us that the modem uses 1W of power on 850/900 MHz, and 2W on 1800/1900 MHz. Our measurements showed the same results, even if the connection was considerably weaker on 1800 MHz than on 900 MHz. So changing the operating frequency of the modem will likely save us some energy. A simple way to change the modems operating frequency, is using the Arduino Band Management program. When you change the frequency it is changed internally in the modem so you don’t have to specify it every time you upload new code

When you run this program you can either choose single frequencies (top three choices) or a combination of several frequencies. If you choose one of the combinations, the Arduino is going to connect to the frequency with the strongest signal. This won’t always be the best in terms of power, so in our case we use the DCS frequency specifically. In Norway (at least) this frequency is not used as much outside of the cities, so we will lose some portability. Make sure the frequency you choose is available in the area you are going to use your Arduino.

Let the Arduino sleep

There are several pages on the internet explaining how to make your Arduino sleep, but the by far easiest way to do this is to use Rocket Scream’s LowPower library. From the code below, you can see that we use the LowPower powerDown function. This puts the Arduino to sleep and sets the watchdog timer to wake it up. The ATmega328 supports sleep up to 8 seconds, so we set the timer to that in the parameters of the function. We also turn off the Analog to Digital Converter and the Brownout Detector to save even more energy.

The biggest problem with making the Arduino sleep, is that it stops counting running milliseconds while it sleeps. Therefore the previous way of posting values every five minutes won’t work anymore. Instead we start counting sleep-cycles. Counting 25 sleep cycles plus the time it takes to get and upload data, we get data spaced somewhere between 4 and 5 minutes apart. You can choose how many sleep cycles you want to wait between each measurement, and the battery is likely to improve with a longer interval (more cycles). If you want to read more about sleep and the watchdog timer, you can take a look at the ATmega328 documentation and Rocket Scream’s description of their library.

void loop(void) {
  if(wait>=25){
    startConnection();
    temperature = temp.getTemp(water);
    datastreams[0].setFloat(temperature);
    temperature = temp.getTemp(air);
    datastreams[1].setFloat(temperature);
    int ret = xivelyclient.put(feed, xivelyKey);
    if(ret == 200){
      digitalWrite(greenLed, LOW);
      delay(100);
      digitalWrite(greenLed, HIGH);
    }
    else{
      digitalWrite(redLed, HIGH);
      delay(100);
      digitalWrite(redLed, LOW);
    }
    closeConnection();
    wait=0;
  }	  	  
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);	  
  wait++;
}

Other things to consider

The Arduino was made to be versatile, not to be used for low power projects. Using the voltage regulator and other standard features of the Arduino, we lose a lot more energy than what we would have if we made a specific board for this specific use case. This guide was made to be simple for others to follow so we decided to only do changes to the program, not the hardware. If you want to lower the power consumption further than we have done here, you should take a look at gammon.com.au/power which has a lot of good tips.

Complete, commented code is available at https://github.com/comoyo/BeachSensor

Comments

TLDR; Test our new video meeting service in your browser at appear.in - built on WebRTC and AngularJS. No installs or login.

We at Comoyo have been interested in WebRTC for a while now, reading about it and experimenting with what is actually possible to do with it. Since our employees work in five different locations (Oslo, Trondheim, Stockholm, Amsterdam, Munich), the need for efficient communication tools is omnipresent. We have tested a lot of video conferencing solutions, who all have their advantages and disadvantages.

So, we thought, why not combine our interest in WebRTC with our need for an easier way to set up video meetings? As summer interns in Comoyo, we were assigned with the task of building an easy-to-use web conference system using WebRTC and HTML5. We were not really sure what would come out of this, but the result turned out to be so good that we decided to open it up to public testing in a beta version.

appear.in was created to achieve one goal: to make it really easy to start a video meeting. To achieve this, we allow users to create a new video room in one click from the frontpage. You add people to the conversation by sharing the URL with them. When they open the URL, they will be taken straight into the room and asked to turn on their webcam and microphone.

Features in the beta version

Like most developers, we do a lot of whiteboard drawing. But to our horror, none of the communication channels we have used to date, have an easy way to draw together right then and there. So to be able to share drawings, while still being able to share screens at the same time (because no one has the time to switch back and forth between tabs), we have often ended up doing this:

Manual whiteboard drawing in video conference

This is of course less than ideal, so one of the first conclusion from our planning was that we wanted to make a video meeting software with a shared whiteboard feature.

Other features that we have included in this initial basic feature set include: - Name your own room (or use a really cool predefined one, generated from a list of 2000 adjectives and animal types) - Muting of local video and audio - Fullscreen support - Several different layouts for different types of conferences - Drag and drop video windows to move them around - Screen sharing

How did we build it? (The technical stuff)

Since WebRTC builds on peer-to-peer connections, we all agreed that the service should have as little of a reliance of a central server as possible. But at the same time, we knew we’d have to have some signaling functionality to/from said server, as specified in the W3C specifications:

“Communications are coordinated via a signaling channel which is provided by unspecified means, …”

So we ended up with this: signaling drawing appear.in

When working with WebRTC a lot of the functionality is hidden from the developer, given that, the only part in the above image that needed work was the signaling. For example, creating a stream is:

getUserMedia({video : true , audio : true}, successCallback, errorCallback);

and then waiting for the callback.

Peer Connections are also supposed to be almost as simple, after adding streams and doing the signaling, it is just supposed to work. And when it’s fully implemented in the browsers, it might. But as of right now there are more than a few bugs in different implementations that require workarounds.

What goes into making appear.in work

The architecture of appear.in has two different parts to it, a frontend which is the app that resides within your browser, and a backend.

The frontend of appear.in is built using AngularJS, Socket.io, WebRTC, Twitter Bootstrap 3 and HTML5, while the backend is built on Node.js using Express and Socket.io. In the end we get a technology stack looking something like this:

architecture drawing appear.in

We are using Angular for a multitude of things including routing, writing custom directives, as well as of course data binding. Using Angular with WebRTC is then easy peasy.

function addNewStream(newStream){
$scope.streams.push(URL.createObjectURL(newStream));
}

in your javascript to push the objectURL to a variable named streams in your scope. Then in your html you just have to do:

<div ng-repeat=”stream in streams”>
		<video ng-src=stream autoplay=”true”>
		</video>
</div>

And just like that, you get a video element with a stream for every video you add using our javascript function. If you have created your layouts with the help of Angular directives, you can just change it to:

<div ng-repeat=”stream in streams” splitscreen=”true”>
		<video ng-src=stream autoplay=”true”>
		</video>
</div>

and get it to be a part of your split screen layout. But we will go more into this in another blog post.

Moving forward with appear.in

We will be working constantly with adding more features and fixing bugs. We know that there are lots of bugs and that it does not work in all scenarios and with various network limitations, but we still want to release it to see if this is something people want us to continue working on.

With this beta release we want people to test the service by using it as they normally would use a video conference or video calling solution. We would love to hear about the situations you are using it in, and how it is working for you!

Feedback regarding call quality can be given in the form that appears when you click leave room and will be sent directly to us.

For any feedback, feature requests and/or bug reports, please contact us at feedback@appear.in, Twitter or Facebook.

Visit appear.in!

Comments

If you didn’t know, Comoyo’s offices in Oslo are located pretty close to the water. With the warm weather we’ve been having lately, many Comoyans spend their lunch break down by the beach, some even bringing towels and swimming gear. That gave us an idea: What better way to demonstrate machine to machine communication than to make a combined water/air temperature sensor? Making and demonstrating a working M2M prototype is the goal of the summer intern project we have been assigned to, so we might as well make something fun while we’re at it!

image Software Engineer Matias Holte enjoying the water at Fornebu, complete with sombrero

That decided, we went out to survey the test site to look for a good placement spot. We found a nice place under the pavilion deck, with a practical crossbar where we could place the test unit.

image

A problem with measuring ocean-connected water is that it is affected by the tides – at high tide, the water at the site is a lot deeper, so we need to wade to the spot. Thankfully, the weather is still warm for now, or it could be a cold affair! Measuring water temperature in salt water, and outdoors to boot, brings with it some challenges. Salt water and electronics don’t mix well, to put it mildly. So we needed to make sure to keep things dry and safe, while still being able to measure accurately. Our solution to this was to put things in a sturdy plastic food storage container, as these are usually pretty water-tight, and then make holes for the sensors and sealing them properly around the leads.

Materials

For this project, we used quite a lot of stuff, ordered off Sparkfun, and bought at Clas Ohlson:

image

For our temperature sensors, we chose a waterproof version for measuring the water, and used heat-shrink tubing to protect the regular sensor we use for air temperature measurements. We decided that air temperature measurements were also relevant, as few people like to go swimming in chilly weather even if the water is quite warm.

Arduino shields are boards that add functionality to the Arduino, plugging in to the pin headers on it. For this project, we use a GSM shield, to be able to send our data to our back-end service.

The GSM shield requires an activated SIM card to be able to connect to the mobile network. The GSM shield comes with a Telefónica/Bluevia SIM that can be activated, but it does not work in Norway, so we had to get a Telenor SIM. Seeing as Comoyo is part of Telenor, this was probably one of the easier parts of this project.

We decided that the easiest way to connect rest of the the components to the Arduino was to make a sort of shield out of stripboard by soldering on male pin headers. Then, we soldered on the connections and components.

image Unfinished stripboard fitting on top of the GSM shield. In use, the stripboard will be pushed all the way down, so that the male pin headers are not visible like here.

Hardware design

image

Having decided on the components and how to attach them, we needed to make a wiring diagram. We used Fritzing, an open-source hardware prototyping tool, to design it. Note that the pin headers are not included, instead the pins used are added as wires directly to the Arduino board. Also, the component placement is mirrored, due to the stripboard only having tracks on one side, and that side facing down. Thankfully, this problem was discovered fairly early on, and only a few components needed to be de-soldered. In the end, we had to be a little creative with the placement of the status LEDs, since they had to be visible and thus on the same side as the tracks.

image

Setting up a backend

Xively (formely Pachube, Cosm) is a cloud platform service for connecting devices to the Internet of Things. It offers an easy way to send data to the service, and an easy way to make applications based on the service and data. There are several other such services as well, but Xively seemed to be the easiest to use, providing plenty of documentation.

Once we have signed up, making a new device feed is very easy. In the developer workbench tab there is a button “+ Add Device”. When adding a device, we can select the device name, description and privacy settings. This brings us to the basic overview screen for this device. To be able to collect any data, we need to start one or more channels. Just like with the devices, there’s a big button that says “+ Add Channel”. Once this is done, keep in mind your channel and device name, and copy the API Key and feed number (locations circled in the image). If you would like to limit permissions, you can even generate a new API Key (using the “+ Add Key” button) with different permissions than the default auto-generated key. More on where to use these keys in the next section.

image

Once you do have data, Xively can show them to you in a handy graph, and the number of feed requests are logged, enabling you to keep an eye on what is going on with your device. You can even make Xively trigger HTTP POST requests on various conditions, if you like, by using the “+ Add Trigger” button below the API Key section. In our case, we’ve set Xively to trigger a POST request to an online web application syncing service when the device feed doesn’t receive any data for a certain period of time. The syncing service then sends us an e-mail about this.

Programming the sensor

In this project we use two input pins for the temperature sensors, and two output pins for the status LEDs. We use pins 8 and 10 for output and 12 and 13 for input, but you may use any available pins. The temperature sensors we use transmit data over a OneWire bus, but we have chosen to use one pin per sensor (which sort of makes OneWire unnecessary). We define the input pins as integers this way:

int air_pin = 12;
int water_pin = 13;
int redLed = 10;
int greenLed = 8;

The program starts by including various libraries. GSM.h is needed to interface with the GSM shield, HttpClient.h and Xively.h are needed to post values to Xively, and OneWire.h adds support for communicating with OneWire devices. The Temperature.h library is a library we have put together, based on this Buildr example to make it easier to get temperature data from the sensors without knowing too much about OneWire. If you would like to learn more about what OneWire is all about, you can check out this page and the links on it.

#include <GSM.h>
#include <HttpClient.h>
#include <Xively.h>
#include <OneWire.h> 
#include <Temperature.h>

Next we define the variables used for the GSM shield. You need the PIN code for your SIM card, the APN (e.g. telenor), username and password (in our case, both are the phone number). You can find the information for your carrier here. This information is needed to set up a GPRS connection to transmit data over the GSM network. We then instantiate three objects of type GSMClient, GPRS and GSM.

#define PINNUMBER "PIN"
#define GPRS_APN "APN"
#define GPRS_LOGIN "USERNAME"
#define GPRS_PASSWORD "PASSWORD"

GSMClient client;
GPRS gprs;
GSM gsmAccess;

Then we create two OneWire objects, one for each sensor, using the pin number as required by the constructor. Since we are not using more than one sensor per pin, these variables are different for each object.

OneWire water(water_pin);
OneWire air(air_pin);

We also need to provide some information to the Xively library for our device to be able to transmit our data where we want it. First we define the feed ID, which is found at the top of the feed’s web page on Xively.com. Then we make three char arrays. One for the API key (again, this can be found on the feed page), one for the water sensor stream, and one for the air sensor stream. The name of the streams need to match their name on the feeds page. Next we create the datastreams, feed, and tell Xively which client to use to upload our data. Lastly, we create the Temperature object we will use to retrieve data from the sensors.

#define FEED_ID 123456789
char xivelyKey[] = "API_KEY";

char myWaterTempStream[] = "water";
char myAirTempStream[] = "air";
unsigned long lastTime = millis();


XivelyDatastream datastreams[] = { 
  XivelyDatastream(myWaterTempStream, strlen(myWaterTempStream), DATASTREAM_FLOAT),
  XivelyDatastream(myAirTempStream, strlen(myAirTempStream), DATASTREAM_FLOAT),
};

XivelyFeed feed(FEED_ID, datastreams, 2);
XivelyClient xivelyclient(client);

Temperature temp;

Now that we have finished defining variables and objects, there are still two functions left: Setup and loop. The setup function runs once when the Arduino is powered, or when the reset button is pressed. We use this to define our inputs and outputs, and start the GPRS connection. We use a boolean variable called notConnected to keep track of connection status. The function gsmAccess.begin() starts the modem, and returns the status of the modem. gprs.attachGPRS() initiates the GPRS connection and returns the status of the connection. While this is not shown in the Arduino examples, these two functions should be called with a delay in between. If the modem returns GSM_READY, and the connection returns GPRS_READY, we are connected and we update notConnected. When we are connected, we light up the green LED, otherwise the red LED is lit.

void setup(void) {
 pinMode(redLed, OUTPUT);
 pinMode(greenLed, OUTPUT);
 boolean notConnected = true;
 while (notConnected) {
    digitalWrite(redLed, HIGH);
    digitalWrite(greenLed, LOW);
    if(gsmAccess.begin(PINNUMBER)==GSM_READY){
      delay(3000);
      if(gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD)==GPRS_READY){
        notConnected = false;
        digitalWrite(redLed, LOW);
        digitalWrite(greenLed, HIGH);
      }
    }
    else{
      delay(1000);
    }
  }
}

The loop function runs continuously as long as the Arduino is powered, only stopping for interrupts, and is where we will do our measurements and upload to Xively. The first thing we do is to check whether one minute (60000ms) has passed. This interval determines how often measurements are done and uploaded. The .getTemp() function in the Temperature library returns the temperature of a sensor using the given OneWire object as a float value. We use this to get the temperature of both our sensors, and put the values into the two data streams.

if((millis()-lastTime)>=60000){
    lastTime = millis();
    temperature = temp.getTemp(water);
    datastreams[0].setFloat(temperature);
    temperature = temp.getTemp(air);
    datastreams[1].setFloat(temperature);

We now have everything we need, and are ready to post the values to Xively. This is done with the xivelyclient.put() function. It takes the feed and API key as input parameters and returns the response code. If the submission was successful (response code 200) we blink the green LED, otherwise we blink the red LED.

int ret = xivelyclient.put(feed, xivelyKey);
    if(ret == 200){
    digitalWrite(greenLed, LOW);
    delay(100);
    digitalWrite(greenLed, HIGH);
}
else{
    digitalWrite(redLed, HIGH);
    delay(100);
    digitalWrite(redLed, LOW);
}

If everything works according to plan, we should now have a working sensor that is uploading two temperature values to Xively, and displaying connection information using two LEDs. You can download the full version of the code over at GitHub: https://github.com/comoyo/BeachSensor

While this code runs well using wall power, it will probably not run longer than 24 hours if you are going to run the sensor on normal batteries. In a later post we will go through some of the things we have done to improve battery life.

Weather-proof enclosure

We chose a sturdy 1-litre food storage box with snap lid to accommodate both the Arduino and GSM shield as well as the battery box. It also has a good seal on the lid. The difficulty lay in making a hole in it that was large enough, but without damaging the rest of the box. We also needed to be able to re-seal the box around the cable pulled through, to keep the water out. We made several attempts with screwdrivers, box cutters and wire cutters, but ended up melting through the box using the soldering iron, with the temperature turned down to avoid burning the plastic. Melting plastic is probably not very good for a soldering iron, but it’s the only thing that worked.

image We may have gone slightly overboard with the glue gun. Notice the scratches from earlier attempts at making a hole.

While the placement of the sensor leads works well with the components inside, they are slightly too close to the lid snaps, making opening and closing the box more difficult. A second revision would probably have them placed closer to the bottom of the box.

Once the box was finished, it was quite easy to strap the box to the beams at the test site with a luggage strap, and using cable ties to fasten the water probe to the deck pillar. The luggage strap is adjustable, making opening the box and switching the batteries relatively easy.

As this post is getting quite long, we’re going to have to round it off here - stay tuned for further adventures in machine to machine communication! We’ll be discussing power usage and battery issues, as well as some problems we encountered during the project.

Comments

A couple of weeks ago, I was one of the organizers of the Norwegian Rubik’s cube championship. “What!? Does that even exist?”, you ask. Yes, it does. There are people in this country who practice hours every day, and call it a sport. A sport which is so nerdy that it deserves a blog post here.

Cubes

The original 3x3x3 together with other puzzles used in the competition.

Rubik’s what?

So I assume that everyone knows what a Rubik’s cube is. This twisty puzzle that we all own, but can’t solve. When I was about 15 I got my first Rubik’s cube, and I solved it! I did not come up with the solution myself of course - that takes years. What I did was that I searched for a guide online. I found a good one, and by the end of the day I could solve it in about 5 minutes. The coming days my times improved drastically. The challenge was no longer to actually to solve the cube, but to solve it fast! I had become a “speedcuber”.

A sport for everyone

So this April over 100 kids, youths, students and parents met at the University of Oslo to fight for the title “Norwegian Rubik’s Cube Champion”. The competition was open to everyone who could solve the cube. People was coming from all over Norway, and even other countries like Sweden and Hungary was represented!

Overview Competitors solved the cube on the stage, and live results appeared as they were registered.

Some of them considered themselves being speedcubers, while others showed up to support their friends, or maybe to try to learn how to solve the puzzle. Each competitor could participate in up to a total of 17 different categories, some of which included solving the cube with only one hand, blindfolded and even with their feet! In some categories other puzzles than the normal 3x3x3 was used. For each category there were multiple rounds, and for each round each person solved their puzzle five times, in order to get an average. So all together during the weekend, people solved cubes over 5000 times!

And the winner is…

The winner of the main category, 3x3x3, was Morten Arborg (17). He solved the cube with an average of impressing 9.32 seconds in the final round. His best solve during the competition was 7.28, which is the fastest time done by a Norwegian ever, and which ranks him number 25 in the world.

Winner

Morten Arborg received a trophy and a check for winning 3x3x3.

To compare, the world record, set by the 16 years old Dutch speedcuber Mats Valk, is 5.55 seconds. Here is the video of him showing us how to do it:

Optimal solution?

In 2010 researchers proved that any configuration of a Rubik’s cube can be solved optimally in 20 moves or less. The team, most of them from Silicon Valley, used about 35 CPU-years of idle computer time donated by Google to essentially solve every possible configuration. If you learn a standard beginners method online, you will probably be able to solve the cube by doing about 150 moves, while the best speedcubers in the world solve it by only doing about 50 turns.

Mats Valk did his 5.55 solve in 49 moves. That was by no mean the optimal solution, but it is still pretty good, especially when we know how fast he did it. Also, he is just a human, so what can we expect? Mats does not calculate the optimal solution, but he divides the problem into substeps, and solve all of them optimally. He knows over 200 different algorithms, which he uses to modify the cube towards the solved position. Also, he is incredibly fast at both recognizing patterns, and to perform the corresponding algorithm. The best speedcubers do over 10 turns per second. To understand how fast this is you should check out the video of Mats, or try it out yourself.

I bet a computer can do it faster!

So who is the fastest at solving the Rubik’s cube? Humans or computers? If we only care about finding a solution, computers are the winners. They can calculate the optimal solution for any configuration of the cube in a matter of seconds, while no human being are able to do that as far as I know. But when we add the requirement to actually make turns on a real Rubik’s cube, the robots gets a problem. Humans are much better at manipulating the cube, and before 2011 I had never seen any robots faster than the current world record holder.

Then I stumbled upon this video of StormCuber II. This robot made out of Lego Mindstorms, connected to a smartphone solves the cube in less than 5.3 seconds. This is also included inspection time, as opposed to the human world record, which makes it even more impressive.

So go buy yourself a cube!

After reading this blog post, I hope you got inspired to buy yourself a new cube, or to blow the dust of the old cube you already have. Try to solve it by yourself, find a guide online, or get a set of Lego Mindstorms. If this four year old kid can do it, then you should be able to do it as well:

Comments

Web Rebels Logo

Web Rebels is a conference that was started in Oslo last year, by a group of frontend developers from the Framsia Meetup. Framsia has been the regular meeting place for frontend developers in Oslo, but a yearly conference opened the possibility of bringing in international speakers.

“Our goal has been to create an informal, but exclusive conference for people who are really dedicated to the topics we cover, interested in meeting other people and share ideas. We also wanted to create a conference which everyone in the world can attend without having to spend all their hard earned cash here in Oslo.”, says Trygve Lie, member of the organizing team and one of the founders of the conference. Conference room Web Rebels

To support the frontend community in Oslo, Comoyo is a sponsor of the conference, and several of our developers are present to share love and candy with participants. During the conference, people can come to our stand and test Geeksphones with Firefox OS on.

Comoyo team at Web Rebels

As a fourth day of the conference, on Saturday May 25th, we are also hosting an App day for developers who want to experiment with making web apps for Firefox OS. Mozilla’s evangelist Christian Heilmann will be there to talk about Mozilla’s ambitions for the OS, and our developer Jan Jongboom will give an intro to how you can build your first web app for Firefox OS. If you register an app idea you want to work on here, you can win a Geeksphone!

RSVP here if you want to take part in the app day!

Comments