{"id":19225269,"url":"https://github.com/jakkra/smartmirror","last_synced_at":"2025-04-16T01:12:34.729Z","repository":{"id":80606602,"uuid":"77261518","full_name":"jakkra/SmartMirror","owner":"jakkra","description":"My MagicMirror running on a Raspberry Pi","archived":false,"fork":false,"pushed_at":"2021-02-06T12:53:06.000Z","size":56504,"stargazers_count":128,"open_issues_count":1,"forks_count":30,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-16T01:12:27.769Z","etag":null,"topics":["home-automation","iot","led-strip","magic-mirror","magicmirror","node","nodejs","philips-hue","raspberry-pi","react","smart-home","smart-mirror","smartmirror","snowboy","voice-recognition"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jakkra.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-12-24T02:30:20.000Z","updated_at":"2025-04-01T08:08:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"14e03375-ab1c-4fbe-9ec3-c1b9165ef617","html_url":"https://github.com/jakkra/SmartMirror","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakkra%2FSmartMirror","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakkra%2FSmartMirror/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakkra%2FSmartMirror/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakkra%2FSmartMirror/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jakkra","download_url":"https://codeload.github.com/jakkra/SmartMirror/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249178217,"owners_count":21225350,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["home-automation","iot","led-strip","magic-mirror","magicmirror","node","nodejs","philips-hue","raspberry-pi","react","smart-home","smart-mirror","smartmirror","snowboy","voice-recognition"],"created_at":"2024-11-09T15:14:27.918Z","updated_at":"2025-04-16T01:12:34.698Z","avatar_url":"https://github.com/jakkra.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SmartMirror\n\nIt's a Magic Mirror, you all know what it is. This is a complete rewrite in React and Node.js of my [original Magic Mirror](https://github.com/jakkra/MagicMirrorPi) written in Java. Everything is improved and it has lots of new functions.\n\nBoth voice recognition and the UI is in Swedish, however English is also supported by setting language to 'en-US' in the config. For porting to other languages take a look in the locales folder, should be pretty straight forward\n\n## Images\n\n\u003cimg src=\"pics/full_less.jpg\"/\u003e\n\u003cp float=\"left\"\u003e\n  \u003cimg src=\"pics/rsz_full.jpg\" width=\"400\"/\u003e\n  \u003cimg src=\"pics/left.jpg\" width=\"400\"/\u003e\n\u003c/p\u003e\n\u003cimg src=\"pics/temps.jpg\"/\u003e\n\u003cimg src=\"pics/rsz_lc.jpg\"\u003e\n\u003cp float=\"left\"\u003e\n  \u003cimg src=\"pics/list.gif\" width=\"400\"\u003e\n  \u003cimg src=\"pics/below.jpg\" width=\"400\"/\u003e\n\u003c/p\u003e\n\u003cimg src=\"pics/rsz_m.jpg\"\u003e\n\nMy [Home automation and monitoring app](https://github.com/jakkra/OneAppToRuleThemAll) which can control the mirror supports iOS, however you must pay to be a developer to run it on an actual device, so I made a simple web app to control the mirror from.\n\n\u003cimg src=\"pics/rsz_web_app.jpg\" width=\"400\" \u003e\n\n## Features\n**Voice Recognation using Google Cloud Speech**\n\nSince Google Cloud Speech costs, I use [Snowboy](https://github.com/Kitt-AI/snowboy) to listen for my hotword \"Spegel\" or \"Mirror\" on english. When it's detected the Mirror records untill end of speech and sends it to Google Cloud Speech. \n\n* Create reminders on my [Home automation and monitoring backend](https://github.com/jakkra/OneBackendToRuleThemAll).\n* Create tasks in a [Wunderlist](https://www.wunderlist.com/) list.\n* Control Philips Hue Lights. Turn on and off individual lamps or all, for example \"Turn the lights off in the bedroom\" or similar.\n* Hide/show individual elements on the Mirror\n* Turning off the Mirror\n* When reading articles/blogs you can skip to next article\n\nAll voice parsing is done very simple, however I tried to make all commands as dynamic as possible. My implementation is nothing fancy, but it works very well with the features I have right now. It looks for keywords in the spoken senetence and tries to extract it's meaning. Extending it with a lot of speech commands will most likely result in chaos. \n\nReminders can be created in various ways (In Swedish, but translated here to english):\n\n* Remind [me] in 20 minutes/hours/days to take a walk.\n* Remind [me] to walk the dog in 2 minutes/hours/days.\n* Remind [me] tomorrow at 12:35 to do the dishes.\n* Remind [me] on **weekday** to wash the car.\n* Remind [me] to buy/shop [more/extra] milk. // Adds it to a Wunderlist list (Shopping list in my case)\n\nWhen a reminder is successfully created, the Mirror will speak something like \"Will remind you to do X\".\n\n**Led strip**\n\nBehind the Mirror I have a RGB led strip with individually controllable leds. The leds can be controlled from my [Home automation and monitoring app](https://github.com/jakkra/OneAppToRuleThemAll).\n\n### Components\nAll components can be individually shown/hidden by the Web App/API endpoint. The default behaviour is configured in the config.\n\n**Shopping list**\n\nIt displays the items on a Wunderlist list (in my case our shopping list).\n\n**Weather**\n\nDisplays current weather including temperature outside, feels like temperature wind speed and direction.\nAlso sunrise/sunset and 5 day forecast.\n\n**Inside temperature**\n\nWhich is retreived from a DS18B20 temperature sensor connected to the Raspberry PI running the Mirror.\n\n**Motion detection**\n\nMotion detection is retreived from a connected PIR motion detector connected to the Raspberry PI.\nWhen motion is detected, a message will appear on the Mirror. It changes depending on the time of the day.\nAlso it notifies my [Home automation and monitoring backend](https://github.com/jakkra/OneBackendToRuleThemAll) that motion was detected, so my [Home automation and monitoring app](https://github.com/jakkra/OneAppToRuleThemAll) will notify me if I'm not at home and someone is in my apartment.\n\n**Swedish news from SVT**\n\nHeadlines and short descriptions are changing in the bottom of the Mirror every 20 seconds or so.\n\n**Spotify currently playing**\n\nShows your currently playing track, because why not.\n\n**Moisture level of a plant**\n\nShows if your plant needs watering, data is sent from a battery powered esp8266 with a moisture sensor, placed in one of our plants.\n\n**OctoPi**\n\nShows some information of your current 3D print, such as the filename, bed/nozzle temperatures and the progress.\n\n## Running locally\n\n### Set up config file\n1. Copy and rename config.js.default to config.js\n2. Edit config.js and select which modules/functions you want to enable\n\n```\nexport const config = {\n  YAHOO_WOEID: '897819',\n  SMHI_COORD: {\n    longitude: '13',\n    latitude: '55.6'\n  },\n  svtNewsUrl: 'https://api.rss2json.com/v1/api.json?rss_url=http%3A%2F%2Fwww.svt.se%2Fnyheter%2Frss.xml',\n\n  serverBaseURL: process.env.NODE_ENV === 'production' ? 'http://localhost:3001' : 'http://localhost:3000',\n  wsServerBaseURL: process.env.NODE_ENV === 'production' ? 'localhost:3001/' : 'localhost:3001/',\n\n  modules: {\n    dateTime: true,\n    wunderlistTasks: false,\n    transfer: false,\n    weather: true,\n    forecast: true,\n    news: true,\n    tempPirSensor: false,\n    googleCloudSpeech: false,\n    philipsHue: false,\n    temperatureGraph: false,\n    articles: false,\n  }\n\n};\n\n```\n\n### Add .env file to add custom config parameters (optional)\n```\nRuleThemAllBackendAccessToken=''\nwunderlistAccessToken=''\nwunderlistClientID=''\nwunderlistListID='' // The ID of the list to fetch/create tasks in.\n\nGOOGLE_APPLICATION_CREDENTIALS = '/home/user/../credentials.json'\nGCLOUD_PROJECT = 'project_ID'\n\nHUE_HOSTNAME='192.168.X.X' // Your bridge IP\nHUE_USERNAME='username' // See https://github.com/peter-murray/node-hue-api\n\ntarget='Krantz-Ubuntu' // Set to 'PI' on your Raspberry Pi. Avoids errors initializing gpio when not on Pi.\n```\n\n\n### \n\n### Run it\n\nNOTE: This project is only tested on Node v7.6.0. New versions of Node may not work.\nIf you get wierd errors, downgrade to Node v7.6.0. \n```\ngit clone https://github.com/jakkra/SmartMirror.git\ncd SmartMirror\nnpm i\n\ncd client\nnpm i\n\ncd ..\nnpm start\n```\n\nNote: The current package.json are compatible with node 7.6.0\nIf you get errors building with later version of node, use below to downgrade: \n```\nsudo npm cache clean -f\nsudo npm install -g n\nsudo n 7.6.0\n```\n\n### Code style \n```\nprettier --print-width 120 --jsx-bracket-same-line --single-quote --trailing-comma es5 --write ./**/*.js\n```\n\n## Building\n\nRunning `npm run build` creates the static bundle.\n\n```\ncd client/\nnpm run build\n```\nMove client/webApp-move2build to client/build and rename it to whatever. It's accessed on \u003chostname\u003e/\u003cwhatever name\u003e afterwards.\n\n## Solutions\nWebpack doesn't reload when saving: \n```\n$echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf \u0026\u0026 sudo sysctl -p\n```\n\nAuto open chrome in SSH on RaspberryPi:\n```\nexport DISPLAY=:0.0\nnpm start\n```\n\n## Useful commands\n```\n$ sudo apt-get install unclutter\n$ unclutter -display :0.0 -idle 5 # Hides cursor after 5 seconds of inactivity\n\n$ export DISPLAY=:0.0 # When starting chromium over SSH this must be done\n$ chromium-browser --kiosk --incognito http://localhost:3001 # Launch Chromium in kiosk mode\n\n$ sudo apt-get install -y fonts-tlwg-sawasdee # Installs the font I use.\n\n$ sudo iptables -t nat -I PREROUTING --source 0/0 --destination 0/0 -p tcp --dport 80 -j REDIRECT --to-ports 3001 # Redirect traffic on port 80 to our server at 3001. Allows access on local network to web app on url \u003chostname\u003e/app.\n$ sudo apt-get install iptables-persistent # Keep iptables after reboots\n# Flashing new software to the arduino from the terminal\n# Install libraries\n$ arduino --install-library \"Adafruit NeoPixel\"\n$ arduino --install-library \"MsTimer2\"\n\n$ arduino --board arduino:avr:uno --port /dev/ttyACM0 --save-prefs # store config\n$ arduino --upload $(pwd)/ledstrip.ino # Flashes the new software\n\n#Find port of CC2531 USB stick\n$ls -l /dev/serial/by-id \n\n```\n\n## Starting and updating the mirror on boot\nSave this file somewhere:\n```\n#!/bin/sh\n\ncd /home/pi/Documents/SmartMirror # Edit to path of project\n\ngit fetch\n\nif [ $(git rev-parse HEAD) != $(git rev-parse @{u}) ]; then\n  echo \"Updating mirror\"\n  git stash # Just incase we wanted to save some change\n  git reset --hard origin/master\n  cd client\n  npm run build\n  cd ..\n  cp -r client/webApp-move2build client/build/app\nfi\n\nNODE_ENV=production /usr/bin/npm run server \u003e mirrorLog.txt  \u0026\nexport DISPLAY=:0.0\n/bin/sleep 30 # Let the server startup before trying to access the website, otherwise we get page not found.\nsudo -u pi chromium-browser --kiosk --incognito http://localhost:3001 # Chromium must not be ran as root.\n```\n\nAdd `@/home/pi/start.sh` to `~/.config/lxsession/LXDE-pi/autostart`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjakkra%2Fsmartmirror","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjakkra%2Fsmartmirror","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjakkra%2Fsmartmirror/lists"}