MagicMirror Forum
    • Recent
    • Tags
    • Unsolved
    • Solved
    • MagicMirror² Repository
    • Documentation
    • 3rd-Party-Modules
    • Donate
    • Discord
    • Register
    • Login
    A New Chapter for MagicMirror: The Community Takes the Lead
    Read the statement by Michael Teeuw here.

    Requesting assistance with GroceryApp module

    Scheduled Pinned Locked Moved Development
    8 Posts 2 Posters 471 Views 2 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C Offline
      CurlyQ12391
      last edited by

      Hello!

      I am still pretty new to MagicMirror and coding, but decided it’d be worth it to attempt to build a custom module since I couldn’t find exactly what I was looking for elsewhere. Which brings me to MMM-GroceryApp; which has been built (to the best of my ability) using Kroger Developer documentation.

      I am at the point where I have the main module config.js, node_helper_js, authorize,js, and the CSS file functioning in a way that doesn’t break the MagicMirror. Unfortunately, thats all that is happening - I can’t see this module at all when MagicMirror runs, the location I put it remains blank. So obviously I am missing something, and because of that I can’t login to authorize the application.

      I changed my repository to public so the code can be viewed there, but I will also post the main and node_helper code below. My MagicMirror config.js for this module is pretty basic:

      {
        module: "MMM-GroceryApp",
        position: "bottom_right" 
      },
      

      NOTE: The app is set to be on the bottom_right of my 3rd page.

      MMM-Kroger.js

      Module.register("MMM-GroceryApp", {
      	defaults: {
      		refreshInterval: 1000 * 60 * 5, // refresh every 5 minutes
      		updateInterval: 1000 * 60 * 5 // update every 5 minutes
      	},
      
      	requiresVersion: "2.1.0", // Required version of MagicMirror
      
      	start: function() {
      		var self = this;
      		Log.info("Starting module: " + this.name);
      
      		//Flag for check if module is loaded
      		this.loaded = false;
      
      		this.sendSocketNotification("CONFIG", this.config);
      	},
      
      	getStyles: function () {
      		return [
      			"MMM-GroceryApp.css"
      		];
      	},
      
      	getScripts: function () {
      		return [
      			"moment.js"
      		];
      	},
      
        getStats: function () {
          this.sendSocketNotification("UPDATE", this.config);
        },
      
      	processData: function(data) {
      		var self = this;
      		this.dataRequest = data;
      		if (this.loaded === false) { self.updateDom(self.config.animationSpeed) ; }
      		this.loaded = true;
      
      		// the data if load
      		// send notification to node_helper.js
      		this.sendSocketNotification("MMM-GroceryApp-NOTIFICATION_TEST", data);
      	},
      
      	// socketNotificationReceived from node_helper.js
       	socketNotificationReceived: function(notification, payload) {
      		 console.log("socketNotificationReceived");
      		if (notification === "STARTED") {
      			this.updateDom();
      		}
      		else if (notification === "CART_DATA") {
      			this.loaded = true;
      			this.processChargeData(JSON.parse(payload).response);
      			this.updateDom();
      		}
      		else if (notification === "PRODUCT_SEARCH") {
      			this.loaded = true;
      			this.processDrivestateData(JSON.parse(payload).response);
      			this.updateDom();
      		}
      		else if (notification === "PRODUCT_DETAILS") {
      			this.loaded = true;
      			this.processVehicleData(JSON.parse(payload).response);
      			this.updateDom();
      		}
      		else if (notification === "LOCATION_DATA") {
      			this.loaded = true;
      			this.processVehicleData(JSON.parse(payload).response);
      			this.updateDom();
      		}
      	},
      
      	getDom: function() {
      		// create element wrapper for show into the module
      		var self = this;
      
      		// create element wrapper for show into the module
      		var wrapper = document.createElement("div");
      		wrapper.style.cssText = "float: right;";
      
      		// Data from helper
      		if (this.dataNotification) {
      			var wrapperDataNotification = document.createElement("div");
      			// translations  + datanotification
      			wrapperDataNotification.innerHTML =  this.translate("UPDATE") + ": " + this.dataNotification.date;
      
      			wrapper.appendChild(wrapperDataNotification);
      		}
      		return wrapper;
      }
      });
      

      node_helper.js

      const NodeHelper = require("node_helper");
      var request = require("request");
      
      module.exports = NodeHelper.create({
      	start() {
      		console.log("Starting node helper for: " + this.name);
      	},
      
      getToken(config) {
      	try {
      		const token = getTokenInternal(config);
      		return token;
          } catch (err) {
      		console.log(err);
      		return "abc";
      	}
      },
      
      getTokenInternal(config) {
      
      	// Set the configuration settings
      	const credentials = {
      		client: {
      			id: config.client_id,
      			secret: config.client_secret
      		},
      		auth: {
      			tokenHost: "https://api.kroger.com",
      			tokenPath: "/v1/connect/oauth2/token"
      		  },
      		  http: {
      			headers: { "User-Agent": "MMM-GroceryApp" }
      		}
      	};
      
      const oauth2 = require("Basic").create(credentials);
      
      	const tokenConfig = {
      		grant_type: config.client_credentials,
      		client_secret: config.client_secret,
      		client_id: config.client_id
      	};
      
      	try {
      		var tokenObject = oauth2.client_secret.getToken(tokenConfig);
      		return tokenObject.access_token;
      	} catch (error) {
      		console.log("Access Token Error", error.message);
      }
      },
      
      	
      getData: function() {
      		var self = this;
      
      function getCartData(token) {
      			request.get({
      				url: baseUrl + "/v1/cart/add",
      				headers: {
      					"Accept": "application/json",
      					"Authorization": "Bearer {{TOKEN}}"
      					  },
      				"processData": false,
      				"data": "{\n  \"items\": [\n     {\n       \"upc\": \"0001200016268\",\n       \"quantity\": \2\\n      }\n    ]\n }"
      				},
      			function (error, response) {
      				if (!error && response.statusCode == 400) {
      					self.sendSocketNotification("CART_DATA", response);
      				}
      			});
      		}
      		function getProductSearch(token) {
      			request.get({
      				url: baseUrl + "/v1/products?filter.brand={{BRAND}}&filter.term={{TERM}}&filter.locationId={{LOCATION_ID}}",
      				headers: {
      					"Accept": "application/json",
      					"Authorization": "Bearer {{TOKEN}}"
      					  },
      			function (error, response) {
      				if (!error && response.statusCode == 400) {
      					self.sendSocketNotification("PRODUCT_SEARCH", response);
      				}
      			}}
      		);
      	}
      		function getProductDetails(token) {
      			request.get({
      				url: baseUrl + "/v1/products/{{ID}}?filter.locationId={{LOCATION_ID}}",
      				headers: {
      					"Accept": "application/json",
      					"Authorization": "Bearer {{TOKEN}}"
      					  },
      			function (error, response) {
      				if (!error && response.statusCode == 400) {
      					self.sendSocketNotification("PRODUCT_DETAILS", response);
      				}
      			}}
      		);
      	}
      		function getLocationData(token) {
      			request.get({
      				url: baseUrl + "/v1/locations",
      				headers: {
      					"Accept": "application/json",
      					"Authorization": "Bearer {{TOKEN}}"
      					  },
      			function (error, response) {
      				if (!error && response.statusCode == 400) {
      					self.sendSocketNotification("LOCATION_DATA", response);
      				}
      			}}
      	);
      	}
      	if (accessToken === null ) {
      			var tempToken = getToken(this.config);
      			var localToken = tempToken.then(function(accessToken){
      				return accessToken;
      			});
      
      			localToken.then(function(token) {
      				accessToken = token;
      				getCartData(token);
      				getProductSearch(token);
      				getProductDetails(token);
      				getLocationData(token);
      		});
      	}
      		else {
      			getCartData(accessToken);
      			getProductSearch(accessToken);
      			getProductDetails(accessToken);
      			getLocationData(token);
      	}
      	},
      
      		socketNotificationReceived: function(notification, payload) {
      		if (notification === "MMM-GroceryApp") {
      			this.sendSocketNotification("MMM-GroceryApp");
      			self.config = payload;
      			self.sendSocketNotification("STARTED", true);
      			self.getData();
      			self.started = true;
      		} else if (notification == "CONFIG") {
      			self.sendSocketNotification("CART_DATA", self.cart_data);
      			self.sendSocketNotification("PRODUCT_SEARCH", self.product_search);
      			self.sendSocketNotification("PRODUCT_DETAILS", self.product_details);
      			self.sendSocketNotification("LOCATION_DATA", self.location_data);
      	    }
      	}
      });
      

      I really appreciate any assistance and/or tips you are able to provide :)

      S 3 Replies Last reply Reply Quote 0
      • S Offline
        sdetweil @CurlyQ12391
        last edited by

        @CurlyQ12391 if u have no notification , then getDom () returns a div with no visible content

        this is why most modules put up a dummy message “Loading…” until data arrives

        if you add console.log() calls in your node helper
        then u can look at the messages in the mm startup messages

        use npm start

        Sam

        How to add modules

        learning how to use browser developers window for css changes

        1 Reply Last reply Reply Quote 0
        • S Offline
          sdetweil @CurlyQ12391
          last edited by

          @CurlyQ12391 also, many of the calls u are making, are not synchronous
          (they return with data only when done)

          but async, they return now(immediately) , and also later when the actual work completes.
          but you assumed u got the answer,

          you could add debugging to the ok (not error) path to trace the calls happening

          Sam

          How to add modules

          learning how to use browser developers window for css changes

          1 Reply Last reply Reply Quote 0
          • S Offline
            sdetweil @CurlyQ12391
            last edited by

            @CurlyQ12391 i made a git repo of this…
            https://github.com/sdetweil/MMM-GroceryApp

            a few problems

            the functions at the end of node_helper use self, but it wasn’t defined
            the socket notification “config” sends back results, but you haven’t got them yet

            but getData() has a flow error… accessToken not defined…

            don’t know what you were trying to do

            I also added the dummy ‘Loading…’ at the end of getDom() (else {'…})

            Sam

            How to add modules

            learning how to use browser developers window for css changes

            C 1 Reply Last reply Reply Quote 0
            • C Offline
              CurlyQ12391 @sdetweil
              last edited by

              @sdetweil, firstly I’d like to apologize for the gap in my response! I broke my main config shortly after posting this and ended up having to re-flashing my SD card and rebuilding my mirror back up the way I had it from scratch.

              I really appreciate you taking the time to answer my question.

              My intent with this module was to basically house my grocery cart, similar to the interface I have on my phone or visiting the website. I think that an easier approach might be to use an iFrame module for the website, but I was really wanting to utilize the authorization token process to prevent having to login each time - since the end goal is to have the Mirror up on the wall without a keyboard/mouse.

              S 1 Reply Last reply Reply Quote 1
              • S Offline
                sdetweil @CurlyQ12391
                last edited by

                @CurlyQ12391 i understood the intent of the module…

                but looking at the specific code in node_helper trying to setup the call to get the data is where I don’t understand your plan

                Sam

                How to add modules

                learning how to use browser developers window for css changes

                C 1 Reply Last reply Reply Quote 0
                • C Offline
                  CurlyQ12391 @sdetweil
                  last edited by

                  @sdetweil my apologies.

                  The code within the node_helper is mostly from the Kroger Developer documentation. However, I am very new to all this and there is a very good chance that I transferred the documentation over incorrectly or in a way that wont work. I may have incorrectly assumed that by using the Kroger Docs/code it would result in getting similar data to what I’d see upon logging into the mobile/desktop site.

                  S 1 Reply Last reply Reply Quote 1
                  • S Offline
                    sdetweil @CurlyQ12391
                    last edited by

                    @CurlyQ12391 np. I was just trying to help you make progress. I know nothing about the API. but couldnt find anything similar to the code in the helper

                    Sam

                    How to add modules

                    learning how to use browser developers window for css changes

                    1 Reply Last reply Reply Quote 0
                    • 1 / 1
                    • First post
                      Last post
                    Enjoying MagicMirror? Please consider a donation!
                    MagicMirror created by Michael Teeuw.
                    Forum managed by Sam, technical setup by Karsten.
                    This forum is using NodeBB as its core | Contributors
                    Contact | Privacy Policy