From a9488bfaf4325b571bd999799a1a9a2e1e40941e Mon Sep 17 00:00:00 2001 From: Lee Lawlor Date: Thu, 19 Mar 2015 11:33:15 -0400 Subject: [PATCH 1/4] update outdated link for Twitter docs --- app/views/docs/thingtweet.html.erb | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 app/views/docs/thingtweet.html.erb diff --git a/app/views/docs/thingtweet.html.erb b/app/views/docs/thingtweet.html.erb new file mode 100644 index 0000000..b845395 --- /dev/null +++ b/app/views/docs/thingtweet.html.erb @@ -0,0 +1,69 @@ +
+ +
+ <%= render 'docs/sidebar' %> +
+ +
+ +

ThingTweet

+ + The ThingTweet App allows you to update a Twitter status via ThingSpeak. Twitter requires Open Authentication (OAuth) which is difficult for a low level device to interface with. ThingTweet acts a Twitter proxy, so the device can use Twitter by making simple API calls. + +

+ +
+

App Setup

+ + Sign in to ThingSpeak, select Apps from the menu, and then click on ThingTweet. +

+ Under the ThingTweet App, select "Link new Twitter account". This will redirect you to Twitter to see if you want the app to have the ability to access your account. You can Allow or Deny the process. Once you have confirmed the right Twitter account, Twitter will send you back to ThingSpeak. +

+ The app generates a ThingTweet API Key for you to use. If you send an HTTP POST with your ThingTweet API Key, then the message will be relayed to Twitter. All of the parameters from the Twitter API (statuses/update) are possible including geolocation. +

+ +
+

Update Twitter Status

+ + To update your Twitter status send an HTTP POST to <%= @ssl_api_domain %>apps/thingtweet/1/statuses/update and include your ThingTweet API key and message. +

+ Example POST: + +
+POST <%= @ssl_api_domain %>apps/thingtweet/1/statuses/update
+     api_key=<%= @thingtweet_api_key %>
+     status=I just posted this from my thing!
+ +
+ The response will be 1 if the update was successful, and -1 if there was an error. +

+ +

Channel Values

+ You can retrieve the last value from a Channel field by including the following in the ThingTweet status: +

+ %%channel_CHANNEL_ID_field_FIELD_NUMBER%% +

+ For example, you can send a Tweet that includes the last value from Channel 1417, field 1: +

+ status=The current CheerLights color is %%channel_1417_field_1%%. + +

+
+

Update Channel Feed and Twitter Status

+ Your Twitter status can also be updated when a Channel feed is updated by specifying the twitter and tweet parameters. +

+ Example Channel feed update that also updates a Twitter status: + +
+POST <%= @ssl_api_domain %>update.json.xml
+     api_key=XXXXXXXXXXXXXXXX
+     field1=73
+     twitter=thingspeaktest
+     tweet=I just posted this from my thing!
+
+ +











+ +
+
+ From bf1fc0897850a88db6d2fda0f899a737fb3ada6f Mon Sep 17 00:00:00 2001 From: Lee Lawlor Date: Mon, 23 Mar 2015 09:16:25 -0400 Subject: [PATCH 2/4] documentation fix --- app/views/docs/channels/_show.html.erb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/views/docs/channels/_show.html.erb b/app/views/docs/channels/_show.html.erb index ff336c7..9f35951 100644 --- a/app/views/docs/channels/_show.html.erb +++ b/app/views/docs/channels/_show.html.erb @@ -8,11 +8,15 @@ To view a specific Channel, send an HTTP GET to
<%= @ssl_api_domain %>channels/CHANNEL_ID.json.xml . -

-Valid parameters: - +
+ +
+
+ Valid parameters: +
    +
  • api_key (string) - User's API Key; please note that this is different than a Channel API key, and can be found in your account details. If this key is provided, the Channel's private details (such as the Channel's API keys) will also be shown. (optional).
  • +
+

Example GET: From a5871fabf6a2e86e709b9405ae8e196f4f475821 Mon Sep 17 00:00:00 2001 From: Lee Lawlor Date: Mon, 23 Mar 2015 10:37:17 -0400 Subject: [PATCH 3/4] updates from Production --- app/controllers/channels_controller.rb | 1 - app/controllers/windows_controller.rb | 117 +++++------------- app/models/feed.rb | 3 +- app/models/window.rb | 24 ++++ app/views/docs/channels/_update_feed.html.erb | 4 +- app/views/docs/tutorials.html.erb | 18 ++- app/views/windows/_hidden_windows.html.erb | 13 +- spec/models/feed_spec.rb | 5 + 8 files changed, 82 insertions(+), 103 deletions(-) diff --git a/app/controllers/channels_controller.rb b/app/controllers/channels_controller.rb index 65f65de..e96d0e1 100644 --- a/app/controllers/channels_controller.rb +++ b/app/controllers/channels_controller.rb @@ -369,7 +369,6 @@ class ChannelsController < ApplicationController feed.longitude = params[:long] if params[:long] feed.longitude = params[:longitude] if params[:longitude] feed.elevation = params[:elevation] if params[:elevation] - feed.location = params[:location] if params[:location] # if the saves were successful if channel.save && feed.save diff --git a/app/controllers/windows_controller.rb b/app/controllers/windows_controller.rb index be0a853..952a9d5 100644 --- a/app/controllers/windows_controller.rb +++ b/app/controllers/windows_controller.rb @@ -1,6 +1,7 @@ class WindowsController < ApplicationController before_filter :require_user, :except => [:index, :html, :iframe] + # hides a window, returns the window id if successful or '-1' if failure def hide window = Window.find(params[:id]) window.show_flag = false @@ -11,60 +12,36 @@ class WindowsController < ApplicationController end end - # Call WindowsController.display when we want to display a window on the dashboard - # params[:visibility_flag] is whether it is the private or public dashboard - # params[:plugin] is for displaying a plugin, instead of a window - # params[:id] is the window ID for conventional windows, but the plugin_id for plugins - # params[:channel_id] is the channel_id + # displays a window on the dashboard def display - @visibility = params[:visibility_flag] - window = Window.find(params[:id]) - window = Window.new if window.nil? window.show_flag = true - #Just save this change, then modify the object before rendering the JSON - savedWindow = window.save + # save this change + saved_window = window.save - config_window window + # modify the object before rendering the JSON + window.set_title_for_display! + window.set_html_for_display! - @mychannel = current_user && current_user.id == window.channel.user_id - - if savedWindow + # if the window was saved successfully + if saved_window render :json => window.to_json else render :json => 'An error occurred'.to_json end end - def config_window(window) - if window.window_type == "plugin" - pluginName = Plugin.find(window.content_id).name - window.title = t(window.title, {:name => pluginName}) - elsif window.window_type == "chart" - window.title = t(window.title, {:field_number => window.content_id}) - options = window.options if !window.nil? - options ||= "" - window.html["::OPTIONS::"] = options unless window.html.nil? || window.html.index("::OPTIONS::").nil? - else - window.title = t(window.title) - end - end - def html window = Window.find(params[:id]) - options = window.options unless window.nil? || window.window_type != "chart" - window.html["::OPTIONS::"] = options unless window.html.nil? || window.html.index("::OPTIONS::").nil? - html = window.html - - render :text => html + window.set_html_for_display! + render :text => window.html end def iframe window = Window.find(params[:id]) - options = window.options unless window.nil? || window.window_type != "chart" - window.html["::OPTIONS::"] = options unless window.html.nil? || window.html.index("::OPTIONS::").nil? + window.set_html_for_display! iframe_html = window.html - + # set the domain correctly iframe_html = iframe_html.gsub(/src=\"[\/.]/, 'src="' + api_domain); render :text => iframe_html end @@ -73,26 +50,16 @@ class WindowsController < ApplicationController channel = Channel.find(params[:channel_id]) windows = channel.public_windows(true).order(:position) unless params[:channel_id].nil? - if channel.recent_statuses.nil? || channel.recent_statuses.size <= 0 + if channel.recent_statuses.blank? @windows = windows.delete_if { |w| w.window_type == "status" } else @windows = windows end @windows.each do |window| - - if window.window_type == "plugin" - pluginName = Plugin.find(window.content_id).name - window.title = t(window.title, {:name => pluginName}) - elsif window.window_type == "chart" - window.title = t(window.title, {:field_number => window.content_id}) - options = window.options if !window.nil? - options ||= "" - window.html["::OPTIONS::"] = options unless window.html.nil? || window.html.index("::OPTIONS::").nil? - else - window.title = t(window.title) - end - + # modify the object before rendering the JSON + window.set_title_for_display! + window.set_html_for_display! end respond_to do |format| @@ -108,21 +75,15 @@ class WindowsController < ApplicationController channel = Channel.find(params[:channel_id]) if @visibility == "private" - @windows = channel.private_windows(false) unless channel.nil? + @windows = channel.private_windows(false) else - @windows = channel.public_windows(false) unless channel.nil? + @windows = channel.public_windows(false) end @windows.reject! { |window| window.window_type == "plugin" } @windows.each do |window| - if window.window_type == "plugin" - elsif window.window_type == "chart" - window.title = t(window.title, {:field_number => window.content_id}) - options = window.options unless window.nil? - options ||= "" - window.html["::OPTIONS::"] = options unless window.html.nil? || window.html.index("::OPTIONS::").nil? - else - window.title = t(window.title) - end + # modify the object before rendering the JSON + window.set_title_for_display! + window.set_html_for_display! end respond_to do |format| @@ -133,26 +94,18 @@ class WindowsController < ApplicationController def private_windows channel = Channel.find(params[:channel_id]) - windows = channel.private_windows(true).order(:position) unless params[:channel_id].nil? + windows = channel.private_windows(true).order(:position) - if channel.recent_statuses.nil? || channel.recent_statuses.size <= 0 + if channel.recent_statuses.blank? @windows = windows.delete_if { |w| w.window_type == "status" } else @windows = windows end @windows.each do |window| - if window.window_type == "plugin" - pluginName = Plugin.find(window.content_id).name - window.title = t(window.title, {:name => pluginName}) - elsif window.window_type == "chart" - window.title = t(window.title, {:field_number => window.content_id}) - options = window.options unless window.nil? - options ||= "" - window.html["::OPTIONS::"] = options unless window.html.nil? || window.html.index("::OPTIONS::").nil? - else - window.title = t(window.title) - end + # modify the object before rendering the JSON + window.set_title_for_display! + window.set_html_for_display! end respond_to do |format| @@ -163,7 +116,6 @@ class WindowsController < ApplicationController def update - logger.info "We're trying to update the windows with " + params.to_s #params for this put are going to look like # page"=>"{\"col\":0,\"positions\":[1,2,3]}" #So.. the position values are Windows.id They should get updated with the ordinal value based @@ -177,21 +129,20 @@ class WindowsController < ApplicationController values = JSON(params[:page]) # .. then find each window and update with new ordinal position and col. - logger.info "Channel id = " + params[:channel_id].to_s @channel = current_user.channels.find(params[:channel_id]) col = values["col"] saved = true - values["positions"].each_with_index do |p,i| - windows = @channel.windows.where({:id => p}) unless p.nil? - unless windows.nil? || windows.empty? - w = windows[0] - w.position = i - w.col = col - if !w.save + values["positions"].each_with_index do |p, index| + window = @channel.windows.where({:id => p}).first unless p.nil? + if window.present? + window.position = index + window.col = col + if !window.save saved = false end end end + # if the windows were saved successfully if saved render :text => '0' else diff --git a/app/models/feed.rb b/app/models/feed.rb index 6f524a9..0426db4 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -48,7 +48,7 @@ class Feed < ActiveRecord::Base # for to_xml, return only the public attributes def self.public_options { - :except => [:id, :updated_at] + :except => [:id, :updated_at, :location] } end @@ -70,7 +70,6 @@ class Feed < ActiveRecord::Base only += [:latitude] only += [:longitude] only += [:elevation] - only += [:location] end # add status if necessary diff --git a/app/models/window.rb b/app/models/window.rb index b1d4d9c..1ffa91d 100644 --- a/app/models/window.rb +++ b/app/models/window.rb @@ -43,5 +43,29 @@ class Window < ActiveRecord::Base window if window.save end + # set the title for display to user; don't save after calling this method + def set_title_for_display! + # if this is a plugin + if window_type == "plugin" + plugin_name = Plugin.find(content_id).name + self.title = I18n.t(title, {:name => plugin_name}) + # else if this is a chart + elsif window_type == "chart" + self.title = I18n.t(title, {:field_number => content_id}) + # else set title for other window types, for example: I18n.t('window_map') = 'Channel Location' + else + self.title = I18n.t(title) + end + end + + # set the html for display to user; don't save after calling this method + def set_html_for_display! + if window_type == "chart" + html_options = options || '' + # replace '::OPTIONS::' if present + self.html['::OPTIONS::'] = html_options if html.present? && html.index("::OPTIONS::").present? + end + end + end diff --git a/app/views/docs/channels/_update_feed.html.erb b/app/views/docs/channels/_update_feed.html.erb index fa70ab2..b07b505 100644 --- a/app/views/docs/channels/_update_feed.html.erb +++ b/app/views/docs/channels/_update_feed.html.erb @@ -64,8 +64,7 @@ POST <%= @ssl_api_domain %>update @@ -92,7 +91,6 @@ POST <%= @ssl_api_domain %>update <longitude type="decimal" nil="true"/> <elevation nil="true"/> - <location nil="true"/> </feed> diff --git a/app/views/docs/tutorials.html.erb b/app/views/docs/tutorials.html.erb index 88bd36c..91b9954 100644 --- a/app/views/docs/tutorials.html.erb +++ b/app/views/docs/tutorials.html.erb @@ -12,7 +12,7 @@
-

Getting Started with ThingSpeak

+

Getting Started with ThingSpeak

C

-

Freetronics

-

Google

+

Raspberry Pi

+

Ruby

Spark Core

Twine

    @@ -136,6 +138,10 @@ +

    Windows PowerShell

    +

    Wireless

    • Connecting XBee Wireless Networks to ThingSpeak via the ConnectPort X2 running XIG
    • diff --git a/app/views/windows/_hidden_windows.html.erb b/app/views/windows/_hidden_windows.html.erb index e920f1a..1d87efd 100644 --- a/app/views/windows/_hidden_windows.html.erb +++ b/app/views/windows/_hidden_windows.html.erb @@ -15,16 +15,13 @@ // add click handler $(document).on('click', '.ioplugin', function() { - var plugins = $(".plugin"); var addPlugin = $(this); var ids = addPlugin.attr('id').split("-"); - var channelId = <%= params[:channel_id] %>; - var windowId =ids[1]; - //Need to add data to this request to identify it as a plugin request - var data = {plugin:true, visibility_flag:"<%= @visibility %>"}; - $.update("/channels/" + channelId + "/windows/"+ windowId + "/display" , data, - function(response) { + var channelId = <%= params[:channel_id] %>; + var windowId = ids[1]; + + $.update("/channels/" + channelId + "/windows/"+ windowId + "/display", {}, function(response) { var window = response.window; var window_type = window.window_type; @@ -79,7 +76,7 @@
      • Windows
      • - <% if @visibility =="private" %> + <% if @visibility == "private" %>
      • Plugins
      • <% else %>
      • Plugins
      • diff --git a/spec/models/feed_spec.rb b/spec/models/feed_spec.rb index b6b797c..499554d 100644 --- a/spec/models/feed_spec.rb +++ b/spec/models/feed_spec.rb @@ -26,6 +26,11 @@ require 'spec_helper' describe Feed do + it "should not include location in feed.to_json" do + feed = Feed.new + JSON.parse(feed.to_json).keys.include?('location').should eq(false) + end + it "should close the connection when an exception is raised" do # use a single connection for both queries connection = ActiveRecord::Base.connection From e27fd396ff58cb0b5a273e9082c91856b592632f Mon Sep 17 00:00:00 2001 From: Lee Lawlor Date: Mon, 30 Mar 2015 09:56:17 -0400 Subject: [PATCH 4/4] fix importer --- app/controllers/channels_controller.rb | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/app/controllers/channels_controller.rb b/app/controllers/channels_controller.rb index e96d0e1..b61f316 100644 --- a/app/controllers/channels_controller.rb +++ b/app/controllers/channels_controller.rb @@ -517,6 +517,14 @@ class ChannelsController < ApplicationController if !row.blank? feed = Feed.new + # set location and status then delete the rows + # these 5 deletes must be performed in the proper (reverse) order + feed.status = row.delete_at(status_column) if status_column > 0 + feed.location = row.delete_at(location_column) if location_column > 0 + feed.elevation = row.delete_at(elevation_column) if elevation_column > 0 + feed.longitude = row.delete_at(longitude_column) if longitude_column > 0 + feed.latitude = row.delete_at(latitude_column) if latitude_column > 0 + # add the fields if they are from named columns, using reverse order feed.field8 = row.delete_at(field8_column) if field8_column != -1 feed.field7 = row.delete_at(field7_column) if field7_column != -1 @@ -527,14 +535,6 @@ class ChannelsController < ApplicationController feed.field2 = row.delete_at(field2_column) if field2_column != -1 feed.field1 = row.delete_at(field1_column) if field1_column != -1 - # set location and status then delete the rows - # these 5 deletes must be performed in the proper (reverse) order - feed.status = row.delete_at(status_column) if status_column > 0 - feed.location = row.delete_at(location_column) if location_column > 0 - feed.elevation = row.delete_at(elevation_column) if elevation_column > 0 - feed.longitude = row.delete_at(longitude_column) if longitude_column > 0 - feed.latitude = row.delete_at(latitude_column) if latitude_column > 0 - # remove entry_id column if necessary row.delete_at(entry_id_column) if entry_id_column > 0 @@ -556,6 +556,10 @@ class ChannelsController < ApplicationController feed.field6 = row[6] if feed.field6.blank? feed.field7 = row[7] if feed.field7.blank? feed.field8 = row[8] if feed.field8.blank? + feed.latitude = row[9] if feed.latitude.blank? + feed.longitude = row[10] if feed.longitude.blank? + feed.elevation = row[11] if feed.elevation.blank? + feed.status = row[12] if feed.status.blank? # save channel and feed feed.save @@ -614,4 +618,3 @@ class ChannelsController < ApplicationController end end -