Help with makeWebRequest for a beginner

I'm not a full-time developer (dabble in Python) and this is my first ConnectIQ, so please bear with me. I've done quite a bit of searching and reading to figure this out and while I've resolved some issues, I'm stuck on this one.

For my first app, I want to make a widget that, when viewed, sends an update to a Slack channel about how far I've run and how far away I am from the office. To do this, I started with the simple watchface sample app and have been adding my makeWebRequest code to function onShow() in the file helloView.mc.

I am currently setting variables for each argument of the request:

function onShow() {
var url = "hooks.slack.com/.../vR0y2342wGe234few2OQ0xHe";
var params = {
"channel" => "#dev",
"username" => "ram-bot",
"text" => "test garmin slack integration",
"icon_emoji" => ":athletic_shoe:"
};
var headers = {
"Content-Type" => Comm.REQUEST_CONTENT_TYPE_URL_ENCODED,
"Accept" => "application/json"
};
var options = {
:method => Comm.HTTP_REQUEST_METHOD_POST,
:headers => headers
};


And then I have the actual request code, and it's commented out for now:

// Comm.makeWebRequest(
// url, params, options, method(:onReceive)
// );


But even with just that, my app doesn't run in the simulator and I get the following console output:

File pushed successfully
Connection Finished
Closing shell and port
Found Transport: tcp
Connecting...
Connecting to device...
Device Version 0.1.0
Device id 1 name "A garmin device"
Shell Version 0.1.0
Permission required
Permission Required
Failed invoking <symbol>
Connection Finished
Closing shell and port


I am trying to run this on a Forerunner920XT and I am working in Eclipse on a Mac. I see that permission required usually means you are trying to access an API that is not available, is there something about setting variables that wouldn't be allowed in this file/function?

Here's the full code for the project for context:


helloView.mc
using Toybox.WatchUi as Ui;
using Toybox.Graphics as Gfx;
using Toybox.System as Sys;
using Toybox.Lang as Lang;
using Toybox.Application as App;
using Toybox.Communications as Comm;

class helloView extends Ui.WatchFace {

function initialize() {
WatchFace.initialize();
}

// Load your resources here
function onLayout(dc) {
setLayout(Rez.Layouts.WatchFace(dc));
}

// Called when this View is brought to the foreground. Restore
// the state of this View and prepare it to be shown. This includes
// loading resources into memory.
function onShow() {
var url = "hooks.slack.com/.../vR0yM234RwGeT69tGaOQ0xHe";
var params = {
"channel" => "#dev",
"username" => "ram-bot",
"text" => "test garmin slack integration",
"icon_emoji" => ":athletic_shoe:"
};
var headers = {
"Content-Type" => Comm.REQUEST_CONTENT_TYPE_URL_ENCODED,
"Accept" => "application/json"
};
var options = {
:method => Comm.HTTP_REQUEST_METHOD_POST,
:headers => headers
};
// Comm.makeWebRequest(
// url, params, options, method(:onReceive)
// );
}

// Update the view
function onUpdate(dc) {
// Get the current time and format it correctly
var timeFormat = "$1$:$2$";
var clockTime = Sys.getClockTime();
var hours = clockTime.hour;
if (!Sys.getDeviceSettings().is24Hour) {
if (hours > 12) {
hours = hours - 12;
}
} else {
if (App.getApp().getProperty("UseMilitaryFormat")) {
timeFormat = "$1$$2$";
hours = hours.format("%02d");
}
}
var timeString = Lang.format(timeFormat, [hours, clockTime.min.format("%02d")]);

// Update the view
var view = View.findDrawableById("TimeLabel");
view.setColor(App.getApp().getProperty("ForegroundColor"));
view.setText(timeString+"\nhello world");

// Call the parent onUpdate function to redraw the layout
View.onUpdate(dc);
}

// Called when this View is removed from the screen. Save the
// state of this View here. This includes freeing resources from
// memory.
function onHide() {
}

// The user has just looked at their watch. Timers and animations may be started here.
function onExitSleep() {
}

// Terminate any active timers and prepare for slow updates.
function onEnterSleep() {
}

}


helloApp.mc
using Toybox.Application as App;
using Toybox.WatchUi as Ui;

class helloApp extends App.AppBase {

function initialize() {
AppBase.initialize();
}

// onStart() is called on application start up
function onStart(state) {
}

// onStop() is called when your application is exiting
function onStop(state) {
}

// Return the initial view of your application here
function getInitialView() {
return [ new helloView() ];
}

// New app settings have been received so trigger a UI update
function onSettingsChanged() {
Ui.requestUpdate();
}

}


helloBackgound.mc
using Toybox.WatchUi as Ui;
using Toybox.Application as App;
using Toybox.Graphics as Gfx;

class Background extends Ui.Drawable {

function initialize() {
var dictionary = {
:identifier => "Background"
};

Drawable.initialize(dictionary);
}

function draw(dc) {
// Set the background color then call to clear the screen
dc.setColor(Gfx.COLOR_TRANSPARENT, App.getApp().getProperty("BackgroundColor"));
dc.clear();
}

}


Any help is greatly appreciated!!
  • Did you enable Communications permission for your project?

    In Eclipse, right-click on your project, select Properties -> Connect IQ
    There you will see a list of permissions, and Communications should be checked.
  • While you say you want a widget, it appears that you are doing a watchface - at least in part (you're extending Ui.Watchface, onEnterSleep(), onExitSleep(), etc). Doing something like comm isn't available for watch faces, and is likely why you're getting the permissions error. Can you turn on the Comm permission of this project? (right click on project, the Properties, then Connect IQ, and you'll see the targets you support and permissions your app wiill need at the bottom.

    What is the type of your app in the manifest.xml? (it's at the end of the second line in the typical file)

    If you're using Eclipse, you can create a project that's a widget and move your code there, and set the Comm permissions, etc.

    In eclipse, under File>New>Connect IQ Project, select "widget" for the project type.
  • thank you thank you!!!

    PERMSSIONS
    - totally missed that, I just saw a long list of Garmin devices and assumed it continued all the way down the form to the end, so yeah, nothing was enabled so I enabled everything for now and that got settings the vars working.

    APP TYPE
    - Yes jim_m_58, you're right. I started the app as a WatchFace, then realized I really wanted a Widget, so I changed the project to a widget, but I still have all the WatchFace code, which I guess works, since it works, but I imagine could cause me problems down the road, so I will need to switch that over.

    COMMUNICATIONS
    - So now I have the app running successfully to set my variables, but when I enable the Comm code and try to run it, I get:

    File pushed successfully
    Connection Finished
    Closing shell and port
    Found Transport: tcp
    Connecting...
    Connecting to device...
    Device Version 0.1.0
    Device id 1 name "A garmin device"
    Shell Version 0.1.0
    Failed invoking <symbol>
    Invalid Value
    in onShow (/Users/Richard/code/connectiq/workspace/hello/source/helloView.mc:41)
    Connection Finished
    Closing shell and port


    (line 41 is where the Comm.makeWebRequest starts)

    Which I assume means I'm getting something wrong with setting my Comm.makeWebRequest args,

    var url = "hooks.slack.com/.../vR0yMQhrRwGeT69tGaOQ0xHe";
    var params = {
    "channel" => "#dev",
    "username" => "ram-bot",
    "text" => "test garmin slack integration",
    "icon_emoji" => ":athletic_shoe:"
    };
    var headers = {
    "Content-Type" => Comm.REQUEST_CONTENT_TYPE_URL_ENCODED
    "Accept" => "application/json"
    };
    var options = {
    :method => Comm.HTTP_REQUEST_METHOD_POST,
    :headers => headers
    };
    Comm.makeWebRequest(url, params, options, method(:onReceive)
    );
    }


    but that I should be able to work on by reading the docs and trial and error. Thanks for the help Jim and HermoT!!!
  • solved! I guess I just had to handle the response somewhere, even if I didn't do anything with it. I just added

    function onReceive(responseCode, data) {
    responseCode.toString();


    to the same class, same file, and it worked!