Author Topic: Connect two Oaks via wifi (no cloud)  (Read 3911 times)

xan

  • Newbie
  • *
  • Posts: 2
Connect two Oaks via wifi (no cloud)
« on: April 05, 2016, 06:23:31 am »
After some reading around, I think this isn't possible, but I'm not familiar enough with the platform to be sure.

TLDR: Can I directly connect one oak to another (one as an ap, the other as a client for example) to allow direct data transmission between the two. Any configuration is fine, but specifically without an "external" wifi network infrastructure.

My use case:

I was hoping to use the Oak's as a wifi-bridge between NMEA (serial) devices on a boat. NMEA data is simple serial strings and specifically I wanted to

* connect one Oak to my AIS receiver (via serial as a NMEA listener)
* connect one Oak to my chartplotter (via serial as a NMEA trasmitter)
* forward the serial AIS messages via wifi, creating a wireless bridge between the two devices.
* Not use any external network (since there wouldn't be one when sailing)

Basically, create a simple, no-infrastructure serial link between the two devices.

I know that I would have to figure out how to send data between the two devices myself (TCPServer/Client was my thinking) in the absence of the cloud environment but if "direct" connection was possible, that shouldn't be hard too send NMEA sentences over TCP (or even UDP, since a malformed message would likely just be ignored by the receiving device in any case, latency isn't much of an issue for this data, and any bad data would be replaced on the next message anyway.

I know that I could potentially use local cloud (in the case of having a permanant wifi network that was not internet connected), but that's more work for me than just abandoning this idea all together and running a cable. I know that running a cable is probably simpler in any case, but I wanted to try out a project using the Oaks, and this was the most immediate that came to mind (as I actually have a need for this).

My reading so far says this isn't possible, any advice much appreciated.

Cheers,

xan

briankb

  • Newbie
  • *
  • Posts: 26
Re: Connect two Oaks via wifi (no cloud)
« Reply #1 on: April 05, 2016, 08:53:52 am »
Did you consider bluetooth?

digi_guy

  • Jr. Member
  • **
  • Posts: 87
Re: Connect two Oaks via wifi (no cloud)
« Reply #2 on: April 05, 2016, 10:02:28 am »
I'm really hoping the answer to this is yes because I'd like to do some similar projects.

In theory you need one of the Oaks to be a server and the other to be a client. The server would be set to AP mode (access point) which would allow it to broadcast an SSID the way a router does, and then "listen" for client requests. The Digispark Pro+wifi was able to do this, and I suspect the Oak is also able to as well, but I'm not smart enough to know how the wifi card is integrated into the Oak.

As a slightly easier version, I know that if you have both Oaks connected to a router (with or without internet) you can have them talk to each other rather easily using their ip address and a port. Here is an example I'm using on one of the Oaks to display a webpage:

Code: [Select]
#include <ESP8266WiFi.h>

WiFiServer server(80);  //the port that requests are made on
char myIpString[24];


void setup() {
    IPAddress myIp = WiFi.localIP();
    sprintf(myIpString, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);
    Particle.publish("ipAddress", myIpString);
 //This displays your Oak's ip address on the Particle cloud. If you use a browser on the same network you can go //ipAddress::port and get this webpage
 
   server.begin();  //starts listening for requests
}

void loop() {
  // listen for incoming clients
  WiFiClient client = server.available();
  if (client) {

    if (client.connected()) {
     Particle.publish("ipAddress", "Connected to client");

      client.println("HTTP/1.1 200 OK");
      client.println("Content-Type: text/html");
      client.println("Connection: close");  // the connection will be closed after completion of the response
      client.println("Refresh: 5");  // refresh the page automatically every 5 sec
      client.println();
      client.println("<!DOCTYPE HTML>");
      client.println("<html>");
      client.println("<head>");
      client.println("<title>Ethernet Tutorial</title>");
      client.println("<meta http-equiv=\"refresh\" content=\"1\">");
      client.println("</head>");
      client.println("<body>");
      client.println("<h1>A Webserver Tutorial </h1>");
      client.println("<h2>Other stuff will go here</h2>");
      client.println("</body>");
      client.println("</html>");
    }
    // close the connection:
    client.stop();
  }
}

I'm working on the client side now.

defragster

  • Sr. Member
  • ****
  • Posts: 467
Re: Connect two Oaks via wifi (no cloud)
« Reply #3 on: April 05, 2016, 12:10:30 pm »
No reason it shouldn't work to start the one OAK as an AP ( based on my understanding of generic ESP8266 ) and then have the other OAK connect to that AP. I don't know if Particle precludes or gets in the way of that.

In either case the OAK should be able to run as a WebServer to generate and respond to standard web stuff - or other messages.  I have not tried that yet but UDP messages seem to be the way to randomly send out messages if you don't use something more specific.

xan

  • Newbie
  • *
  • Posts: 2
Re: Connect two Oaks via wifi (no cloud)
« Reply #4 on: April 05, 2016, 03:44:58 pm »
Thanks for the responses! Using one Oak as an AP, connecting with the other and then doing Server+client code stuff to pass data from one to the other was exactly what I assumed / hoped would be possible. Unfortunately I didn't get time to read up on the tech etc. behind the Oaks that much so I'm coming at this pretty fresh.

Do you know of a good place for documentation on the libraries available for the Oak? I've read a lot of the particle docs (as linked from the wiki), but mostly the cloud libraries and wifi connection stuff (turning wifi on off etc). Maybe I've just missed the guts of it, but it's mostly seemed geared towards to cloud, even the bits that don't seem that "cloudy".

For example, is there a good canoical source documentation for the stuff from ESP8266WiFi.h as digi_guy posted?

Many thanks again for the help, I'm excited to see if I can get this working (mostly for the fun of it), assuming I can get 2/3 of my Oaks to first update  ::)

EDIT:

Finally had time to do a bit more digging and came across this sample from the IDE " WiFiTelnetToSerial - Example Transparent UART to Telnet Server for esp8266" (will post code below for convenience...)

Basically, this looks to be 1/2 of exactly what I want to do. Here it's bridging telnet to serial, basically echoing anything it recieves over telnet onto the serial connection. I would do this but also the reverse at the other end, echoing serial out over telnet!

I'm not in a position to unbrick my Oak (not got the correct cables etc) - does anyone know with any degree of certainty if this code (of the main components of it) will run on the Oak? Are there any major changes that are required? I'm not asking for a complete solution, just to know if this is the right starting point in terms of capability of the hardware!!

Thanks again.

xan

Code: [Select]
/*
  WiFiTelnetToSerial - Example Transparent UART to Telnet Server for esp8266

  Copyright (c) 2015 Hristo Gochkov. All rights reserved.
  This file is part of the ESP8266WiFi library for Arduino environment.
 
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#include <ESP8266WiFi.h>

//how many clients should be able to telnet to this ESP8266
#define MAX_SRV_CLIENTS 1
const char* ssid = "**********";
const char* password = "**********";

WiFiServer server(23);
WiFiClient serverClients[MAX_SRV_CLIENTS];

void setup() {
  Serial1.begin(115200);
  WiFi.begin(ssid, password);
  Serial1.print("\nConnecting to "); Serial1.println(ssid);
  uint8_t i = 0;
  while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500);
  if(i == 21){
    Serial1.print("Could not connect to"); Serial1.println(ssid);
    while(1) delay(500);
  }
  //start UART and the server
  Serial.begin(115200);
  server.begin();
  server.setNoDelay(true);
 
  Serial1.print("Ready! Use 'telnet ");
  Serial1.print(WiFi.localIP());
  Serial1.println(" 23' to connect");
}

void loop() {
  uint8_t i;
  //check if there are any new clients
  if (server.hasClient()){
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      //find free/disconnected spot
      if (!serverClients[i] || !serverClients[i].connected()){
        if(serverClients[i]) serverClients[i].stop();
        serverClients[i] = server.available();
        Serial1.print("New client: "); Serial1.print(i);
        continue;
      }
    }
    //no free/disconnected spot so reject
    WiFiClient serverClient = server.available();
    serverClient.stop();
  }
  //check clients for data
  for(i = 0; i < MAX_SRV_CLIENTS; i++){
    if (serverClients[i] && serverClients[i].connected()){
      if(serverClients[i].available()){
        //get data from the telnet client and push it to the UART
        while(serverClients[i].available()) Serial.write(serverClients[i].read());
      }
    }
  }
  //check UART for data
  if(Serial.available()){
    size_t len = Serial.available();
    uint8_t sbuf[len];
    Serial.readBytes(sbuf, len);
    //push UART data to all connected telnet clients
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      if (serverClients[i] && serverClients[i].connected()){
        serverClients[i].write(sbuf, len);
        delay(1);
      }
    }
  }
}
« Last Edit: April 05, 2016, 03:58:10 pm by xan »

PeterF

  • Hero Member
  • *****
  • Posts: 881
Re: Connect two Oaks via wifi (no cloud)
« Reply #5 on: April 05, 2016, 11:30:28 pm »
You can always just hit compile in the Arduino IDE and see if there are any nasty error messages, as some incompatible stuff seems trigger error messages in the IDE if you use them.

For instance,

Code: [Select]
   
WiFi.begin(ssid, password);
                             ^
exit status 1
call to 'ESP8266WiFiClass::begin' declared with attribute error: You must use the WiFi config mode to change the Oaks network info.

Changing it to WiFi.begin(); fixed that problem, as once you have connected your Oak to a wireless network, you don't need to specific the SSID or password, and can just use WiFi.begin() without any parameters. Otherwise compiled without any issues, and is loading on an unsuspecting Oak. Code is running on the Oak, and Particle says it's still alive. However, I'm not sure if the code is doing anything. Serial 1's TX should be P0 (ESP8266 GPIO2) on the Oak if I'm reading the GPIO mapping correctly, but nothing is coming out of it. The Oak isn't bricked though, and is still responding to new code being uploaded, so no issues there.

As far as Particle / cloud stuff... you can always issue a Particle.disconnect() command to disable Particle. However, you won't be able to OTA programming using Particle until you issue a Particle.connect() command to reconnect (or just go into safe mode).



digi_guy

  • Jr. Member
  • **
  • Posts: 87
Re: Connect two Oaks via wifi (no cloud)
« Reply #6 on: April 07, 2016, 12:57:04 pm »
I did a bunch of digging, and turns out it's a lot easier than I thought.

On the server side of things the modified Oak libraries simply requires:

Code: [Select]
    WiFi.enableAP();
    WiFi.softAP("name_of_SSID");

This turns on the Oak's access point, while also maintaining the STA function (I don't think that can be turned off). The next thing that as to happen is to turn on the server
Code: [Select]
WiFiServer server(80);
server.begin();

The last stage is to then connect to a client
Code: [Select]
void loop() {
  // listen for incoming clients
  WiFiClient client = server.available();
  if (client) {

    if (client.connected()) {
      client.println("Print stuff to the client");
     
      while (client.available()) {    //check if there is incoming data from the client
        String path = client.readStringUntil('/r'); //read the data
        Particle.publish("request", path.c_str());  //publish it to the Particle cloud
        delay(250);
        }
     }
  }

} //end loop

Now I need to work on the client side.

digi_guy

  • Jr. Member
  • **
  • Posts: 87
Re: Connect two Oaks via wifi (no cloud)
« Reply #7 on: April 07, 2016, 01:13:00 pm »
It seems the client side is a lot harder. Normally we should be able to call WiFi.begin("name_of_SSID"); and connect to a wifi network. This has been disabled, so the only way to change it is to go through the external wifi config setup.

ETA:  So far I haven't been able to get one oak to connect to another. I think there are some default features that are trying to connect to the particle cloud.
« Last Edit: April 07, 2016, 01:35:11 pm by digi_guy »

digi_guy

  • Jr. Member
  • **
  • Posts: 87
Re: Connect two Oaks via wifi (no cloud)
« Reply #8 on: April 07, 2016, 03:12:15 pm »
Success!!!

Sort of...

Here is the code for the server side that will act as an access point, broadcast an SSID, then publish a message to the particle cloud:

Code: [Select]
#include <ESP8266WiFi.h>

WiFiServer server(80);
char myIpString[24];

void setup() {
    WiFi.enableAP();
    WiFi.softAP("insertSSID");
    server.begin();
}

void loop() {
  // listen for incoming clients
  WiFiClient client = server.available();
  if (client) {

    if (client.connected()) {
     Particle.publish("Server", "Connected to client");
     while (client.available()) {
        String path = client.readString();
        Particle.publish("Server", path.c_str());
        }
    }
  }
}


Dealing with the client is a massive pain in the ass since you'll have to first run that oak.exe so you can upload sketches. When you're done you'll have to go into the config mode and change the wifi setup to have it connect to your server. This sketch will connect to the server and send a time stamp every second. Another word of warning, for some reason there is a 3 minute delay from when I power on the client until I get my first message. And then the server only lasts a few minutes before it crashes.

Code: [Select]

#include <ESP8266WiFi.h>
 
WiFiClient client;
IPAddress server(192,168,4,1);  //you'll want to verify this is the write ip address that your server-oak is issuing

char publishString[40];


void setup() {
  WiFi.begin();
}


void loop() {
  unsigned long now = millis();
  if (client.connect(server, 80)) {
    // now is in milliseconds
    unsigned nowSec = now/1000UL;
    unsigned sec = nowSec%60;
    unsigned min = (nowSec%3600)/60;
    unsigned hours = (nowSec%86400)/3600;
    sprintf(publishString,"%u:%u:%u",hours,min,sec);
    client.println(publishString);
  }

  delay(1000);
}


digistump

  • Administrator
  • Hero Member
  • *****
  • Posts: 1465
Re: Connect two Oaks via wifi (no cloud)
« Reply #9 on: April 08, 2016, 12:33:29 pm »
try adding SYSTEM_MODE(SEMIAUTOMATIC) to the top - this will prevent the Oak from auto connecting to Particle (or auto attempting) - you'll need to call Particle.connect() to connect
or SYSTEM_MODE(MANUAL) which will prevent the auto connect and not automatically check particle for new data each loop when connected.

A bit more about those can be found here (for now):https://docs.particle.io/reference/firmware/photon/