CaySimple - Homemade Android App Demo / Toolkit

Here is a homemade Android App demo and toolkit. You can edit in your own username/password, and your devices/sensors, and download it to your android device, or cut and paste and make up your own interface. The top 1/3 of the screen is a scrolling list of status, errors, and exceptions which you can drag up to see old messages. The bottom 1/3 shows 4 boxes containing 4 datapoints with value, unit time and data, and how old the data is. And the middle 1/3 shows 24 hour graph of the bottom two datapoints. 8 hours of the 24 hours is visible and you drag to the left or right to see the entire sample.

See later for more instructions about how it works, and what the buttons do, but first here are the instructions to install.

Step 1
Download and install Android Studio - its free.

Step 2
Go to GitHub - jameszah/CaySimple: Simple Android App to display Cayenne mydevices.com data and history and download the zip file containing the project.
github

Step 3
Unzip the file and open it with Android Studio using the “Open an existing project …” and selecting the folder of the unzipped CaySimple project.

Step 4
Open the directory
Project → app → java → com.james.caysimple → SimpleActivity and edit in your cayenne username and password, and 2 devices and 4 sensors. I use 3 sensors on one device, and the 4th sensor on another device. Change that as you choose. The sensors shown will not work for you, as they are mine.

You can get the device / sensor numbers 8x-4x-4x-4x-12x by opening your web dashboard, then clicking on the Settings in the upper-right of the sensor, and then the url showing on your browser should look like this:

https://cayenne.mydevices.com/cayenne/dashboard/esp8266/af749630-e884-11e7-848a-61efd1c01e7d/settings/ddb68760-e889-11e7-8934-ff70c6ef636b

The first 8x-4x-4x-4x-12x is the device, and the second is the sensor.


userpass

Step 5
Open the directory
Project → app → res → layout → activity_simple.xml and fiddle around as you choose. On this snapshot it shows the device is a Galaxy s7, which is not one of the pre-installed options. The boxes will all get shuffled around for larger or smaller screens, so you may have to make the boxes smaller to fit everything in for your device. There is a bit of a learning curve figuring out how to fiddle with all the boxes and settings.

Step 6
Connect your android device to the computer with a usb.
Your android device will need to be set up to receive a downloadable program from your pc. Instructions here:

Step 7
Click the Run ‘app’ button and it will compile, download, and run the app on your device.

Step 8
Obviously you will have to go through the java code and change the scales on the graph, and sizes of boxes for your data.

Usage Instructions

When the CaySimple app starts, it first checks if it can access the internet by checking the time. The time is printed in the box at the top of the screen. You can click the GET TIME button, to re-query and print the time in the box.

If it can access the internet, then CaySimple will turn on the GET CAY AUTH button, and then send your username/password to Cayenne to get your Authorization Token. It will print it in the box at the top. You can re-query it by clicking the GET CAY AUTH button. The box at the top of the screen scrolls down, but you can drag it back up to see the information that runs off the bottom.

Finally, if you successfully get your Auth Token, then it will turn on the CAY DATA button. Click the CAY DATA button and it will send 6 queries to Cayenne, and about 500ms later the data should appear in the 4 blue boxes, and the last 24 hours of data will be queried for the two temperature sensors that are the bottom two sensors in the blue boxes. See the java code for which sensor goes in which box. The code also shows how to change colors on the 3rd box based on the value of the sensor.

The graph starts with the most recent data on the right, and then 8 hour old data on the left, and you can drag the graph to see the last 24 hours of data.
The times in the Cayenne database are UTC time, and they are all changed in the code to Mountain Standard Time with the -7 hours calculations. You can edit that for your own timezone. The standard java timezone functions to too difficult to understand, so I just subtracted the seconds.

The box at the top will show each data point arriving, and the time/date of the data, and how old the data is in seconds, and the milliseconds it took between the query and the response from cayenne.

Also you can click the bottom two blue boxes to update those 2 temperatures, without requesting all 4 points and redrawing the graph. Obviously you will have different sensors in those boxes.

The important bits of the java code:

getTime() - gets the time and prints it in the top box (to confirm internet is working
getCayenneAuth() - gets your Authorization Token based on your username/password

The heart of the program is the class CayDataPoint. You create a datapoint with

currentTemp = new CayDataPoint(deviceID, sensorIDtemp, (TextView) findViewById(R.id.newDataTemp));

where deviceID and sensorID are the 8x-4x-4x-4x-12x numbers of your sensor and newDataTemp is the name of a box on your screen where the data and time will be deposited when the information arrives from Cayenne.

The “new CayDataPoint” call just creates the object. When you want the data, you call currentTemp.update(); and the object will request it from Cayenne, and put it in the box newDataTemp, and also store it in the object, so you can access the value and time with currentTemp.v and currentTemp.ts. Be aware you cannot access these values immediately after the update() call, as it will take 500ms or up to 10,000ms for Cayenne to respond and store the data in currentTemp.v If Cayenne does not respond within 10 seconds, you will get a timeout message in the box at the top to the screen. The box will also contain error messages and exception messages if things are going wrong. To draw a datapoint on the graph, you call currentTemp.updategraph(), and it will request 24 hours of data and put it on the graph for the currentTemp sensor.

This is just a starting point to make it easier to access the data. You could add a dozen DataPoints with nice drawings of your machinery, or multiple graphs, and fiddle with how you want the time displayed, if at all.

Also, use at your own risk.

The app aborted plenty of times during the development, and caused no problems with my Samsung Galaxy S7, but you never know. You can just re-start the app, or edit the code and xml screen layout, and then run the app again, and it will download and store itself on your device. And you can delete it in the usual way of deleting apps.

Let me know if anyone gets it working, or have questions.

The tutorials of Neoxelox were the starting point of this app, and contain detailed explanations on the cayenne REST API calls.

8 Likes

@jameszahary Great job i will test !

Hi, the open-source cayenne android java object is coming along nicely, but I have an Authorization question.

I want to build an app to give to other people (normal pre-compiled android app for non-programmers), that accesses my sensors, but does not have my username/password compiled into the code. I assume this is the purpose of the “Create App” with the “APP KEY” and the “APP SECRET”. But I cannot find anything about assigning my sensors to the “App” and then generating an Authorization Token, that I substitute for username/password generated token. Or do I send the APP KEY or APP SECRET in place of the Authorization Token?

I am correct in the assumption that “Create App” does this job?
And could someone send along the 2-3 GETs or PUTs I need to do to get that working?

Hi @jameszahary

Very cool what you have done. Here’s a link to our sample application with detail calls API calls and oAuth flow.

I have to do all this, and reverse engineer some code, to understand how it works? A couple of paragraphs of text would be preferable.

You don’t have to install the application. The readme has enough information to understand API calls and auth flow. In addition, here’s the documentation page for our Platform API Cayenne Docs

Furthermore, it sounds like what you are trying to accomplish is a kind of sharing capability. We don’t support such feature at the moment.

ok, after some reading …

It seems to me that the Cayenne API is a replacement for the Cayenne website - creating accounts, adding devices, sensors, rules, … all with high quality authentication. It might be used if I am mass producing devices and accounts, and the website is not adequate. But who is doing that?? :grinning:

I was looking for more accessing and displaying the data, with 2-3 devices and a dozen sensors, and perhaps some controls to send messages from a phone to cayenne to the device.

On the matter of sharing sensors: you have the system of sharing “projects” which lets a non-authenticated user look at a webpage of values. I tried copying the device/sensor numbers (which have changed from the logged-in version of the same device/sensor) to access the data with an app, but it doesn’t work. (unless i copied the numbers wrong) That is an option of opening that existing “public” system to give access to the same data within an app.

New version of the simple Cayenne app – notably for the cayenne.java object.

Once you copy the cayenne.java app, the rest is easy.

First, create the object

myCayenne = new Cayenne(cayenneemail, cayennepassword, -7, ErrorStatusBox); // -7 for Mountain, -5 for Eastern, etc

Second, get authenticated.

myCayenne.getCayenneAuth();

Third (optional), get a list of all your devices and sensors

myCayenne.getThings();

This function fills some data structures

myCayenne.SensorArrayList is a list of the names of device and sensor, plus the deviceID and sensorID numbers, and hashmaps

myCayenne.NameIDhashmap

and

myCayenne.IDNamehashmap

to convert names to numbers and back.

Fourth, get some data the easy way.

You create the object for the data point with the deviceID and sensorID, and give it the name of the box to deposit the result when it arrives is 500ms or so. Your program can continue without suspending the user interface waiting for the data. When you want it refreshed, you call the update function.

myCayDataPoint = myCayenne.new CayDataPoint(deviceID, sensorID, (TextView) findViewById(R.id.textDP));

myCayDataPoint.update();

Fifth, get some data the fancy way.

The fancy way sets up a callback function, so your program will be alerted and you can do some post-processing to display, manipulate, and react to the data when it arrives in 500ms or so. This example changes some colors and stores the various bits of the data in boxes.

            myCayDataPoint.myResponse.addListener(new Cayenne.CayDataPointRecd() {
            public void CayDataPointRecdHandler_Callback() {

            myCayenne.AddtoBigBox("data handler");

            TextView tv = findViewById(R.id.textDPv);
            tv.setText(String.valueOf(myCayDataPoint.v));

            if (myCayDataPoint.v > 20) {
                tv.setBackgroundColor(Color.RED);
            } else {
                tv.setBackgroundColor(Color.WHITE);
            }

            tv = findViewById(R.id.textDPts);
            tv.setText(myCayDataPoint.ts);
            tv = findViewById(R.id.textDPunit);
            tv.setText(myCayDataPoint.unit);
            tv = findViewById(R.id.textDPdevice_type);
            tv.setText(myCayDataPoint.device_type);
        }
    });

    myCayDataPoint.update();

And Sixth, draw a graph of your data

You specify the box to draw the graph, 0 or 1 for left or right axis, color of the line, and lower/upper bounds, or just provide the same number if you don’t know the bounds.

myCayDataPoint.updategraph(gv, 0, Color.BLUE, 0.0, 0.0);

Okay, see the example code - easier than typing into this little box.

See the example code as the getCayenneAuth() and getThings() also have callback functions, to launch the next request when the previous one completes.

1 Like

The display I set out to produce a few weeks ago:

1 Like

Latest member of the CaySimple family … CayWidget.
Blue box at the top - still needs some high tech artistic flourishes - and a title.

1 Like

could you share this “CayWidget” code ? on Github ?
Thanks

ok, in a day or two.
Had to redesign to add a graph, and not sure which old version still works. :grinning:

:rofl: Like all the makers we are , we always start something, and as soon as it works, we want to make a new one

1 Like

CayWidget

This program installs a widget on your Android device, and displays two Cayenne data points every 15 minutes, or whenever you click the Update button. The upper-right shows the time of last update, then the two data points with the device name and sensor name from the Cayenne setup, then the value and units, and an indication of how old the data was when it was displayed: -10s or -3h for 10 seconds and 3 hours old. At the bottom is a status box for errors or messages about clicks or Android events.

CayWidget

Personalize Instructions

  1. Edit CayIntentService.java to put in cayenne username/password, and the device id and sensor id for two cayenne data points.

  2. Edit cay_app_widget.xml to redraw the box for more features

  3. Edit cay_app_widget_info.xml to change widget update from 900000 ms (15min) to something else

  4. Compile and install - see instructions earlier in this post for setting up Android device to download from a computer

Programming Info

CayAppWidget.java - just handles the Update button and calls CayIntentSerice.java to do the work

CayIntentService.java - does all the interaction with Cayenne, and writes the results into the widget. The heart of the code is creating the cayenne and caydatapoint objects, then calling getCayenneAuth to login to cayenne, and getThings to get a list of your devices and sensors (used here only to get your device/sensor names), and calling update to fetch the fresh values of the data. All these functions are synchronous, as the IntentService only operates on one thread. Names such as appwidget_t1 and timebox are the names of boxes on the widget screen, found in cay_app_widget.xml.

     String cayenneemail = "MrPeanut@gmail.com";
     String cayennepassword = "peanutpassword";

    String devID1 = "bd7309e0-2e04-11e8-822e-bbf389efce87";
    String senID1 = "44979b00-2e39-11e8-9beb-4d400e603e7e";
    String devID2 = "bd7309e0-2e04-11e8-822e-bbf389efce87";
    String senID2 = "41989860-2e24-11e8-82f6-390cc0260849";

    Cayenne myCayenne;
    Cayenne.CayDataPoint Temp1;
    Cayenne.CayDataPoint Temp2;

    try {

        view = new RemoteViews(getPackageName(), R.layout.cay_app_widget);

        myCayenne = new Cayenne(cayenneemail, cayennepassword, -6, null);
        myCayenne.sync_getCayenneAuth();

        if (myCayenne.CayAuthToken != ""){

            myCayenne.sync_getThings();

            Temp1 = myCayenne.new CayDataPoint(devID1, senID1, null);
            Temp2 = myCayenne.new CayDataPoint(devID2, senID2, null);

            String t1 = Temp1.sync_update();
            String t2 = Temp2.sync_update();

            if (Temp1.Date_ts != null){
                view.setTextViewText(R.id.appwidget_t1,  Temp1.sensorname + " " + t1);
            } else {
                view.setTextViewText(R.id.appwidget_t1,  "First: bad point ???");
            }

            if (Temp2.Date_ts != null) {
                view.setTextViewText(R.id.appwidget_t2,  Temp2.sensorname + " " + t2);
            } else {
                view.setTextViewText(R.id.appwidget_t2,  "Second: no response ???");
            }

            view.setTextViewText(R.id.timebox, String.valueOf(DateFormat.format("h:mm:ssaa", System.currentTimeMillis())));

        } else {

            view.setTextViewText(R.id.appwidget_t1, " ");
            view.setTextViewText(R.id.appwidget_t2, " ");
            view.setTextViewText(R.id.timebox, " ");

            view.setTextViewText(R.id.appwidget_text2, String.valueOf(DateFormat.format("h:mm:ssaa", System.currentTimeMillis())) + " " + "Cayenne auth failed");
        }

Okay, that’s all for now.

3 Likes

@jameszahary this looks cool.thank you for the code. :slight_smile: i will surely give it a try.

yes me to !

if you could help me with the widget mine are 3 universal digital sensor with position 1 or 0 and a temperature sensor could be and that in turn send email or notification in the apk
thanks masters

i compiled witch my data ids and widget
1 bad point
2no response???
what??

Couple of bits of code for cutting and pasting.

  1. Instead of the perilous attempt to retype 72 chars of hex device and sensor ids, here is the code to get the first sensor of your first device, so we know you own it, and it is typed correctly. The getThings call get a list of all your stuff.

            String firstDevSen = myCayenne.hashMap.keySet().toArray()[0].toString();
            String dev = firstDevSen.substring(0,36);
            String sen = firstDevSen.substring(36,72);
    
            Temp1 = myCayenne.new CayDataPoint(dev, sen, null);
    
  2. Code to access a binary device, and then check if it belongs to you, and then use it to change some colors on the widget. Black for 0, Red for 1, Grey for others, and Yellow for no response or bad data point. (must be run after the getThings call.)

            Cayenne.CayDataPoint BinaryPoint;
            String devID3 = "12345678-e884-11e7-848a-61efd1c01e7d";
            String senID3 = "12345678-085d-11e8-8620-addae6ef14ff";
            
            BinaryPoint = myCayenne.new CayDataPoint(devID3, senID3, null);
            String bp = BinaryPoint.sync_update();
          
            String key = devID3+senID3;
            if (myCayenne.hashMap.containsKey(key)){
                if (BinaryPoint.Date_ts != null) {
                    if (BinaryPoint.v == 0){
                        view.setInt(R.id.appwidget_t2, "setBackgroundColor", Color.BLACK);
                    } else if (BinaryPoint.v == 1){
                        view.setInt(R.id.appwidget_t2, "setBackgroundColor", Color.RED);
                    } else {
                        view.setInt(R.id.appwidget_t2, "setBackgroundColor", Color.GRAY);
                    }
                } else {
                    view.setInt(R.id.appwidget_t2, "setBackgroundColor", Color.YELLOW);
                }
            } else {
                String x = key.replaceAll("-","");
                view.setTextViewText(R.id.appwidget_t2, "bad devID/senID => " + x);
            }
    

Sorry help me …in sensor settings no format sensor corrrect.?.. watch
https://cayenne.mydevices.com/cayenne/dashboard/raspberrypi/34c098a0-161d-11e8-aeac-8375e928efd4/settings/d4793a04a6b4c03d5b8ca9451ba0ba761714ec00