• Recent
  • Tags
  • Unsolved
  • Solved
  • MagicMirror² Repository
  • Documentation
  • 3rd-Party-Modules
  • Donate
  • Discord
  • Register
  • Login
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 469 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 Aug 21, 2022, 5:38 PM

    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 Aug 21, 2022, 5:46 PM Reply Quote 0
    • S Away
      sdetweil @CurlyQ12391
      last edited by Aug 21, 2022, 5:46 PM

      @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 Away
        sdetweil @CurlyQ12391
        last edited by Aug 22, 2022, 1:20 PM

        @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 Away
          sdetweil @CurlyQ12391
          last edited by Aug 22, 2022, 5:21 PM

          @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 Sep 23, 2022, 1:38 AM Reply Quote 0
          • C Offline
            CurlyQ12391 @sdetweil
            last edited by Sep 23, 2022, 1:38 AM

            @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 Sep 23, 2022, 2:17 AM Reply Quote 1
            • S Away
              sdetweil @CurlyQ12391
              last edited by Sep 23, 2022, 2:17 AM

              @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 Sep 23, 2022, 2:53 AM Reply Quote 0
              • C Offline
                CurlyQ12391 @sdetweil
                last edited by Sep 23, 2022, 2:53 AM

                @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 Sep 23, 2022, 3:16 AM Reply Quote 1
                • S Away
                  sdetweil @CurlyQ12391
                  last edited by Sep 23, 2022, 3:16 AM

                  @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