Controlling the photon outside of local network

Hello !

Im struggling to understand how i would go forward to be able to controll the photon from a website. No, not locally. But from a website, anywhere in the world. Im able to do it on the local network. I dont think theres many more steps to it. But how? I keep searching but i can not find anything. Im not very good at servers and stuff like that. So im probably just using wrong words in the search field. I followed a guide. Anyway, here is “my” code so far:

// This #include statement was automatically added by the Particle IDE.
#include <MDNS.h>

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_ST7735.h>

MDNS mdns;

//tft pins
#define cs   A2
#define dc   A1
#define rst  A0

Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst); // hardware spi

#include "WebServer.h"
WebServer webserver("", 80);

#define POST_NAME_LENGTH    32
#define POST_VALUE_LENGTH   32

// Our "settings"
String myValA = "B";
String myValB = "hello world";
bool myValC = true;

// All pages
P(Page_start) = "<!DOCTYPE html><html><head><title>My Device</title><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><meta charset=\"UTF-8\"></head><body>";
P(Page_css) = "<style type=\"text/css\">html,body{font-family:sans-serif;}fieldset{margin-left:auto;margin-right:auto;max-width:480px;border-radius:8px;}</style>";
P(Page_end) = "</body></html>";

// Form-specific
P(Form_css) = "<style type=\"text/css\">p{clear:both;width:100%;line-height:1.5em;}label{width:49%;text-align:right;display:inline-block;line-height:1.5em;float:left;margin-left:-1em;}select,input[type=\"text\"]{width:49%;text-align:left;float:right;}#c{text-align:left;float:left;margin-left:2em;}</style>";
P(Form_settings) = "<form method=\"POST\" action=\"save.html\"><fieldset><legend>MyDevice Config</legend><p><label for=\"a\">First Setting</label><select id=\"a\" name=\"a\"><option value=\"r\">Red</option><option value=\"g\">Green</option><option value=\"B\">Blue</option></select></p><p><label for=\"b\">Second Setting</label><input type=\"text\" id=\"b\" name=\"b\"></p><p><label for=\"c\">Third Setting</label><input type=\"checkbox\" id=\"c\" name=\"c\"></p><p> </p><p><label for=\"s\"> </label><input type=\"submit\" id=\"s\" value=\"Save\"></p></fieldset>"; 
P(Form_javascript1) = "<script type=\"text/javascript\">";
P(Form_javascript2) = "window.onload=function(){$a=document.querySelector('#a');$b=document.querySelector('#b');$c=document.querySelector('#c');$a.value=a;$b.value=b;if(c==1)$c.checked=\"checked\";}";
P(Form_javascript3) = "</script>";

// Save page
P(Save_fieldset) = "<fieldset><legend>MyDevice Config</legend><p>Your settings have been saved. You will be redirected in 5 seconds, or click <a href=\"/\">here</a> to continue.</p></fieldset>";
P(Save_redirect) = "<meta http-equiv=\"refresh\" content=\"5;URL=/\">";

// Fail page
P(Fail_message) = "<p>Not here. Go away.</p><p>ಠ_ಠ</p>";

// index.html
void web_index(WebServer &server, WebServer::ConnectionType type, char *, bool) {


    server.printP("var a=\""+String(myValA)+"\";");
    server.printP("var b=\""+myValB+"\";");
    server.printP("var c="+String(myValC ? 1 : 0)+";");



// save.html
void web_save(WebServer &server, WebServer::ConnectionType type, char *, bool) {
    char name[POST_NAME_LENGTH];
    char value[POST_VALUE_LENGTH];


    bool c = 0;

    // Loop through POSTed data
    while(server.readPOSTparam(name, POST_NAME_LENGTH, value, POST_VALUE_LENGTH)) {
        // Because strings are easier to test/manipulate
        String _name = String(name);
        String _value = String(value);

            myValA = _value;

        else if(_name.equals("b"))
            myValB = _value;

        else if(_name.equals("c"))
            c = 1;

    myValC = c;

// Bad requests
void web_fail(WebServer &server, WebServer::ConnectionType type, char *, bool) {


void setup() {
    bool mdns_success = mdns.setHostname("mydevice");

    if(mdns_success) {
        mdns.addService("tcp", "http", 80, "MyDevice Config");

    webserver.addCommand("index.html", &web_index);
    webserver.addCommand("save.html", &web_save);

    tft.initR( INITR_GREENTAB );


    tft.setCursor(0, 0);
    tft.print("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, fringilla");

    tft.drawLine(0, 0, tft.width()-1, tft.height()-1, ST7735_YELLOW);
    tft.drawLine(tft.width()-1, 0, 0, tft.height()-1, ST7735_YELLOW);

    tft.drawPixel(0, tft.height()/2, ST7735_GREEN);


void loop() {

    char web_buff[64];
    int web_len = 64;

    webserver.processConnection(web_buff, &web_len);


void updateText() {
			int wut = 1;
      tft.setCursor(80, wut);
      tft.fillRect( 78,  14,  28,  22, ST7735_BLACK);


Ill say thank you in advance for any answer :slight_smile: Please help.

I haven’t gone through your code, but if you want your Photon act as Web Server accessible from anywhere you need to either use a dynamic DNS service like dynDNS or set have your primary router (the one connected to the net) set up with a static IP and configure port forwarding so that any request targeted at that IP but meant for your Photon can get forwareded to it.

mDNS won’t help you with that.

If you haven’t got a static IP to “enter” your LAN from outside, you could have the Photon request its public IP and provide that info via a Particle.variable() to anybody in posession of a valid access token.
Then they can use that IP plus your forwarded port number to contact your webserver.

1 Like

Okay. Thanks for replying. I do have some more keywords now. But still, im a little lost. Do you know of anyone who has done this? Is there any detailed guide for the photon?

For me to understand something i need to see the whole thing. I should have written that im useless at servers, instead of not very good.

This should work:

1 Like

Your code suggests you want to use the Photon as web server, but if you only want to remote control the Photon I’d suggest you go with its inbuilt features first as to which the post by @Moors7 has pointed you.

These are the easy entry points for connected devices, and if they provide what you want, you can maybe forget all the extra “hassle” I outlined above.
If you need to use the Photon as web server, there won’t be a way around getting to understand TCP routing first. While that’s beyond the scope of this community there are countless resources to be found in the WWW.


Ahh okay! Thank you both ! That tutorial should work ! Should…

Looks so simple…

Okay. So it looks like this right:

Servo myservo;  // create servo object to control a servo

int pos = 0;    // variable to store the servo position

void setup()
  pinMode(A4, INPUT);
  myservo.attach(A4);  // attaches the servo on the A0 pin to the servo object
  Particle.function("setpos", setPosition);
  Particle.variable("getpos", &pos, INT);

void loop()


int setPosition(String posValue) {
    pos = posValue.toInt();
    return 0;
  <script src="" type="text/javascript" charset="utf-8"></script>
    <P>Set Water Cup Position:<br><br>
    <input type="range" name="degBox" id="degBoxId" min="0" max="180" step="1" value="90" list="myData" onchange="setValue(this)">
    <!-- This adds the tick marks to the range but does not in Safari -->
    <datalist id="myData">
       <option value="0">
       <option value="30">
       <option value="60">
       <option value="90">
       <option value="120">
       <option value="150">
       <option value="180">
    <button id="minusbutton" onclick="fineAdjust(-5)">&lArr; -5 &deg;</button>
    <button id="plusbutton"  onclick="fineAdjust(+5)">+5 &deg; &rArr;</button>
        <input type ="button" type id="ledOn" onClick="ledSwitch(true)" value ="Lys på">
         <input type ="button" type id="ledOff" onClick="ledSwitch(false)" value ="Lys av">
    <P>Current Position: <span id="curPos"></span><br></P>
    <P>Moisture level: </P>
    <P>Led intensity:</P>
    <P>Kansje happiness level: </P>

    <script type="text/javascript">
      var deviceID    = "1234567890"; 
      var accessToken = "123456787912345676545434321";
      var setFunc = "setpos";
      var getFunc = "getpos";
      var setLight = "setlight"
      var lightBool = null;

      window.setInterval(function() {
        requestURL = "" + deviceID + "/" + getFunc + "/?access_token=" + accessToken;
          $.getJSON(requestURL, function(json) {
                 document.getElementById("curPos").innerHTML = json.result + "&deg;";
                 document.getElementById("curPos").style.fontSize = "28px";
                 document.getElementById("degBoxId").value = parseInt(json.result);
      }, 1000);

      function setValue(obj) {
        var newValue = document.getElementById('degBoxId').value;
      function fineAdjust(value) {
        var currentValue = parseInt(document.getElementById('curPos').innerHTML);
        var setValue = value + currentValue;
        document.getElementById("degBoxId").value = setValue;

      function sparkSetPos(newValue) {
	var requestURL = "" + deviceID + "/" + setFunc + "/";
        $.post( requestURL, { params: newValue, access_token: accessToken });
    function lightSwitch(hehei) {
    var requestURL ="" + deviceID +"/" + setLight +"/";
        $.post(requestURL, {params: hehei, access_token: accessToken});
    function getHumidity() {


I am able to controll trough
But not trough dropbox.

Im supposed to rename it from spark to particle right? Both seems to work though, atleast trough the website. Thats you Moors7? :slight_smile:

This is old syntax

  Particle.variable("getpos", &pos, INT);

we now write

  Particle.variable("getpos", pos);

Hm okay. So ive changed that… I dont think it works still. Hmmm

Nope that wouldn’t correct the issue you had, that was just a heads-up since the old syntax may get deprecated some time and the new syntax is just that bit more readable.

However, when you run the HTML page, what does your browser console report while you are trying it?

Ah, i see. It says that its unsafe and that its trying to load scripts from unauthenticated sources. I have given the browser permission to do this. Its no longer https and its says unsafe.

Edit: In chrome !

Have you tried running the HTML page from your local drive?

I have now and that works !

1 Like

Yup, that would be me :wink:

Nowadays, you can also use the or the Particle app to call those functions/variables :slight_smile:

Thanks alot for the help. I just sent it to a friend in Poland ! She can control it! Niiiice !!! Is it technology or is it magic?! I dont know anymore.

Ah okay ! Wouldnt learn as much tho :slight_smile: