Thinger client on OpenWRT

Evenin’

Haven’t gotten to compile it with libssl support…

But at least it runs and connects to iot.thinger.io on OpenWRT running on Carambola2 device…

root@OpenWRT:~# thingerio 
[3826331.561000]: Not connected!
[3826331.563000]: Connecting to iot.thinger.io:25200 ...
[3826331.914000]: Connected!
[3826331.915000]: Authenticating...
[3826332.325000]: Authenticated!
1 Like

Cool, how did you manage to compile it?

How? Quick and dirty hack…no cmake involved…needs lot of cleanup and nice integration into the make menuconfig system…

At least it also connects now with SSL (o;

root@OpenWRT:~# /sbin/thingerio 
[3827837.935000]: Not connected!
[3827837.938000]: Connecting to iot.thinger.io:25202 ...
[3827839.666000]: Connected!
[3827839.667000]: Authenticating...
[3827839.719000]: Authenticated!

I mean on what OS did you compile it and what modifications so you could target openWRT? my OpenWRT device has very limited flash - so I cant install any compiling libraries.

You always have to compile OpenWRT on Linux…I am using Debian 9…
you might get away on macOS on a case-sensitive filesystem…but it is 15 years ago I cross-compiled Linux images on Mac (o;

Thinger application isn’t that big:

root@OpenWRT:~# ls -l /sbin/thingerio 
-rwxr-xr-x    1 root     root         53285 Oct 24 10:47 /sbin/thingerio

But you can save space in not using SSL as libssl and libcrypto are heavy:

root@OpenWRT:~# ls -l /usr/lib/libssl.so.1.0.0 
-rw-r--r--    1 root     root        320496 Oct 24 10:47 /usr/lib/libssl.so.1.0.0
root@OpenWRT:~# ls -l /usr/lib/libcrypto.so.1.0.0 
-rw-r--r--    1 root     root       1430860 Oct 24 10:47 /usr/lib/libcrypto.so.1.0.0

As mentioned above I am using Carambola2 which has 16MB of flash…dunno what platform you have…

The IoT device is OpenWRT 2.0 MB flash. I think the left should be enough for the binaries.
I’m interested in the instructions of compiling Thinger client on Linux (I have Ubuntu) and targeting OpenWRT.

Have you already flashed it with an own OpenWRT image?
How much space is left on the flash when you log in?

I’ve spent the whole day understanding Thinger. I had never been in touch with such IoT, I’m just hobbist. Neither I had cross-compiled anything. By other hand, I’m very used to Openwrt and C programming, PICs and Arduino. So it was just matter of time.
After fighting for a while, researching and trying, I sucessfully crosscompiled Thinger into my Openwrt router!

It’s very easy once you know what to do. Thinger uses cmake, we can tell cmake what compiler to use.
I used Ubuntu 18.10 with no problems.

Install basic dependencies:

sudo apt-get update
sudo apt-get -y install dkms build-essential git-core libssl-dev libncurses-dev unzip gawk zlib1g-dev subversion mercurial cmake

Download Openwrt source.

(Current Openwrt Stable version: 18.06.02)

    git clone https://github.com/openwrt/openwrt.git
    cd openwrt
    git checkout v18.06.2
    ./scripts/feeds update -a
    ./scripts/feeds install -a

Configure Openwrt

make menuconfig

Now select your Target System and Target profile, and exit saving changes.

Build

make

You can speed it up by using multicore processing

make -j5 (Your CPU cores+1)

Depending on your system, it will take a while.
It took 20 minutes on mine (i7-3770K running at 4.4GHz, 16GB RAM, running on SSD), however, my old Athlon X2 6400 would take 2 hours!
I don’t remember having any errors, I used a fresh Ubuntu system and installed only those dependencies I said.

Download Thinger source:

git clone https://github.com/thinger-io/Linux-Client.git
cd Linux-Client

Edit

Now edit the CMakeLists:

gedit CMakeLists.txt

I deleted all the stuff related with arduino, openssl, etc… as SSL libraries use a lot of space that small routers don’t have!

#---------------------------------------------------------------------------------------------------------------------------
#Change this lines for your Openwrt router. Mine is a WDR4900 with PowerPC processor
#Typical Atheros router will have Mips architecture
#Check the stanging_dir in your openwrt directory and correct these lines.
#---------------------------------------------------------------------------------------------------------------------------
>
set(tools /home/user/openwrt/staging_dir/toolchain-powerpc_8540_gcc-7.3.0_musl)
set(CMAKE_C_COMPILER ${tools}/bin/powerpc-openwrt-linux-musl-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/powerpc-openwrt-linux-musl-g++)

#   #Don't edit past this !
cmake_minimum_required(VERSION 2.8.9)
project(thinger)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")

#check c++11 support
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
    message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

SET(OPEN_SSL 0)
set(SOURCE_FILES src/main.cpp)
add_executable(thinger ${SOURCE_FILES})
target_link_libraries(thinger ${ADDITIONAL_LIBS})
set_target_properties(thinger PROPERTIES COMPILE_DEFINITIONS "DAEMON=0")

Save, and you’re ready!

Edit your src/main.cpp file for your needs.

This was my first test. Yes, it’s ugly as hell, but it works!
I did a simple program that reads the first line of the file /tmp/readings.txt, converts the read string into int and sends the result to Thinger.
I have another script running on Openwrt that read the serial port and updates that file.
As the file is located in /tmp, it’s stored in the ram, so no stress is done to the flash.

#include "thinger/thinger.h"
#include <stdlib.h>
#include <stdio.h>

#define USER_ID             "MyUserID"
#define DEVICE_ID           "MyDeviceID"
#define DEVICE_CREDENTIAL   "MyDeviceCredential"

int watts;

int GetWatts(void){

 FILE *fp;
 char str[16];

   /* opening file for reading */
   fp = fopen("/tmp/readings.txt" , "r");
   if(fp == NULL) {
      perror("Error opening file");
      return(-1);
   };

    fgets(str, 10, fp);                      // Read the first line from the file */
    str[strlen(str)] = '\0';                 // Attach a null character to the end of the string 
   fclose(fp);                                 // Close file

   int w = atoi(str);                       // Convert the string into integer
   return w;
};


int main(int argc, char *argv[])
{
	thinger_device thing(USER_ID, DEVICE_ID, DEVICE_CREDENTIAL);
	thing["Contador"] >[](pson& out){
	    out["Watts"] = watts;
	    };
	while(1){
		thing.handle();
		watts=GetWatts();	
		thing.stream(thing["Contador"]);		
		sleep(5);
	};

	return 0;
};

Now it should compile flawlessly:

sudo chmod +x ./run.sh
./run.sh

However, as the run.sh script runs the executable after compiling, it will drop and error, absolutely normal, because the file is made for our router’s architecture, not our computer’s.
As long as you see this at the end, it’s OK

[100%] Built target thinger

Transfer the file to openwrt

The easiest way is by scp, as it comes installed in ubuntu by default:
(Assuming we still are inside the Linux-Client folder)

 cd build
 scp thinger root@192.168.1.1:/usr/bin

Will ask for the password, and done. Of course, you should have set a password in openwrt or the SSH won’t work.

Now enter the openwrt shell by ssh or telnet:

Important

Thinger needs the libstdc library to work:
opkg update
opkg install libstdcpp

Make thinger executable

chmod +x /usr/bin/thinger

Now it should work!

 root@OpenWrt:/# thinger
 Error opening file: No such file or directory
 [830216.665000]: Not connected!
 [830216.666000]: Connecting to iot. thinger. io:25200 ...
 [830216.767000]: Connected!
 [830216.767000]: Authenticating...
 [830216.827000]: Authenticated!
 Error opening file: No such file or directory

Of course, that error is because I didn’t create the /tmp/reading.txt file! But the client is working

Let’s try something quick:

root@OpenWrt:/# echo "1234">/tmp/readings.txt
root@OpenWrt:/# thinger
[830337.401000]: Not connected!
[830337.402000]: Connecting to iot. thinger. io:25200 ...
[830337.457000]: Connected!
[830337.457000]: Authenticating...
[830337.518000]: Authenticated!

Now my Thinger bucket was receiving data! of course just ""1234.

Good luck everyone! :slight_smile:

1 Like

Thank you for the nice tutorial! just one question, is the target CPU relevant in the compilation process?
My OpenWRT is running on “ar71xx”.

Sorry, I just noticed. The target selection is done at this point: “make menuconfig”

Of course, it’s the most important part, as it will download and install the correct compiler.
Ar71xx is MIPS architecture,while others may be ARM, PowerPC, etc.
That’s why you need to correct these lines:

set(tools /home/user/openwrt/staging_dir/toolchain-powerpc_8540_gcc-7.3.0_musl)
set(CMAKE_C_COMPILER ${tools}/bin/powerpc-openwrt-linux-musl-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/powerpc-openwrt-linux-musl-g++)

I got some errors during compilation.

– Configuring done
– Generating done
– Build files have been written to: /home/user/crosscompile/openwrt/Linux-Client/build
[ 50%] Building CXX object CMakeFiles/thinger.dir/src/main.cpp.o
mips-openwrt-linux-musl-g++: error: “: No such file or directory
mips-openwrt-linux-musl-g++: fatal error: no input files
compilation terminated.
/bin/sh: 1: -std=c++11”: not found
CMakeFiles/thinger.dir/build.make:62: recipe for target ‘CMakeFiles/thinger.dir/src/main.cpp.o’ failed
make[3]: *** [CMakeFiles/thinger.dir/src/main.cpp.o] Error 127
CMakeFiles/Makefile2:67: recipe for target ‘CMakeFiles/thinger.dir/all’ failed
make[2]: *** [CMakeFiles/thinger.dir/all] Error 2
CMakeFiles/Makefile2:79: recipe for target ‘CMakeFiles/thinger.dir/rule’ failed
make[1]: *** [CMakeFiles/thinger.dir/rule] Error 2
Makefile:118: recipe for target ‘thinger’ failed
make: *** [thinger] Error 2

my cmakelist looking like this:

set(tools /home/user/crosscompile/openwrt/staging_dir/toolchain-mips_24kc_gcc-7.3.0_musl)
set(CMAKE_C_COMPILER ${tools}/bin/mips-openwrt-linux-musl-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/mips-openwrt-linux-musl-g++)
#Don’t edit past this !
cmake_minimum_required(VERSION 2.8.9)
project(thinger)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} “${CMAKE_SOURCE_DIR}/cmake/modules/”)
#check c++11 support
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG(“-std=c++11” COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG(“-std=c++0x” COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -std=c++11”)
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -std=c++0x”)
else()
message(STATUS “The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.”)
endif()
SET(OPEN_SSL 0)
set(SOURCE_FILES src/main.cpp)
add_executable(thinger ${SOURCE_FILES})
target_link_libraries(thinger ${ADDITIONAL_LIBS})
set_target_properties(thinger PROPERTIES COMPILE_DEFINITIONS “DAEMON=0”)

Is this path correct? Double check everything…

/home/user/crosscompile/openwrt/staging_dir/

I did triple check; all paths seem ok. Do you think your instructions missing something towards the mips?

When I run cmake …/ every things look smooth:

– The C compiler identification is GNU 7.3.0
– The CXX compiler identification is GNU 7.3.0
– Check for working C compiler: /home/user/crosscompile/openwrt/staging_dir/toolchain-mips_24kc_gcc-7.3.0_musl/bin/mips-openwrt-linux-musl-gcc
– Check for working C compiler: /home/user/crosscompile/openwrt/staging_dir/toolchain-mips_24kc_gcc-7.3.0_musl/bin/mips-openwrt-linux-musl-gcc – works
– Detecting C compiler ABI info
– Detecting C compiler ABI info - done
– Detecting C compile features
– Detecting C compile features - done
– Check for working CXX compiler: /home/user/crosscompile/openwrt/staging_dir/toolchain-mips_24kc_gcc-7.3.0_musl/bin/mips-openwrt-linux-musl-g++
– Check for working CXX compiler: /home/user/crosscompile/openwrt/staging_dir/toolchain-mips_24kc_gcc-7.3.0_musl/bin/mips-openwrt-linux-musl-g++ – works
– Detecting CXX compiler ABI info
– Detecting CXX compiler ABI info - done
– Detecting CXX compile features
– Detecting CXX compile features - done
– Performing Test COMPILER_SUPPORTS_CXX11
– Performing Test COMPILER_SUPPORTS_CXX11 - Success
– Performing Test COMPILER_SUPPORTS_CXX0X
– Performing Test COMPILER_SUPPORTS_CXX0X - Success
– Configuring done
– Generating done
– Build files have been written to: /home/user/crosscompile/openwrt/Linux-Client/build

Try with “sudo”?

1 Like

Found the problem!
I copied the CMakeLists.txt from you as is. Some how the double quotes " are becoming something else ” somewhere in the copy/paste process.

Corrected the post, used preformatted text instead of block quote, that way it works!

Thank you for the efforts in making this cross-compilation possible.

I think I hit a deadly end.
My openWRT device is running barrier_breaker 14.07-rc3 which doesn’t seem to have a “libstdcpp” package. Upgrading is not a good idea due to limit of onboard memory.

Filesystem Size Used Available Use% Mounted on
rootfs 1.0M 364.0K 660.0K 36% /
/dev/root 2.0M 2.0M 0 100% /rom
tmpfs 14.2M 56.0K 14.1M 0% /tmp
/dev/mtdblock3 1.0M 364.0K 660.0K 36% /overlay
overlayfs:/overlay 1.0M 364.0K 660.0K 36% /
tmpfs 512.0K 0 512.0K 0% /dev