MagicMirror Forum

    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unsolved
    • Solved
    • MagicMirror² Repository
    • Documentation
    • Donate
    • Discord

    Requesting assistance with GroceryApp module

    Development
    2
    8
    178
    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
      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
        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

        Create a working config
        How to add modules

        1 Reply Last reply Reply Quote 0
        • S
          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

          Create a working config
          How to add modules

          1 Reply Last reply Reply Quote 0
          • S
            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

            Create a working config
            How to add modules

            C 1 Reply Last reply Reply Quote 0
            • C
              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
                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

                Create a working config
                How to add modules

                C 1 Reply Last reply Reply Quote 0
                • C
                  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
                    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

                    Create a working config
                    How to add modules

                    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 Paul-Vincent Roll and Rodrigo Ramírez Norambuena.
                    This forum is using NodeBB as its core | Contributors
                    Contact | Privacy Policy