Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposed v2.0.0-dev] Extensible REST API, Dynamic Menus, and Socket Communications, plus other updates #104

Merged
merged 46 commits into from
Feb 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
be8b530
es.json
Varguit Dec 8, 2017
3b2d4eb
my changes
BKeyport Dec 3, 2018
6d7a3b6
Direct socket connection proof of concept.
Dec 9, 2018
67a390b
Replace all GetWithStatus calls with socketNotifications
Dec 9, 2018
12a2763
Fix alert encoding
Dec 9, 2018
c476f8c
Basic API implemented, add Socket responses
Dec 9, 2018
439a59c
Fix this and self issues
Dec 9, 2018
f59aabb
Add remainder of get calls to api
Dec 9, 2018
b86171b
Add module show/hide/force to API
Dec 10, 2018
8f267fa
Partial implementation of External APIs
Dec 10, 2018
da86d1c
Update es.json
Varguit Dec 15, 2018
04da9f9
Create ca.json
Varguit Dec 15, 2018
19416c3
Update es.json
Varguit Dec 15, 2018
825bc0e
Additional Changes for sync to remote machine
Dec 16, 2018
a3de407
Working GuessExternalAPI function and added API/README
shbatm Dec 16, 2018
95267c7
Relocate API functions to separate file and update API README
shbatm Dec 17, 2018
fe4132a
Update API documentation and additional changes
shbatm Dec 17, 2018
dfcb03d
Added additional internal functions
shbatm Dec 18, 2018
c5a062a
Implement automatic updates of module list
shbatm Dec 20, 2018
ed8ff85
Implement automatic updates of module list
shbatm Dec 20, 2018
9401291
Bug fix - typo
shbatm Dec 20, 2018
242bb18
Bug Fix Typo
shbatm Dec 20, 2018
a2a1165
Working CONFIG SAVE function via SocketNotification
shbatm Dec 20, 2018
8ea7891
Fine Tuning - remove last GET calls from remote.js
shbatm Dec 21, 2018
bba045f
Added Electron controls (minimize, toggle fullscreen, open devtools)
shbatm Dec 21, 2018
a6e98bc
[2.0.0-dev] Developer Release of Remote Control with REST API
shbatm Dec 21, 2018
116ce80
Merge pull request #1 from Varguit/master
shbatm Dec 21, 2018
e0e2beb
Merge remote-tracking branch 'AgP42/master' into develop
shbatm Dec 21, 2018
ae422f6
Merge 'BKeyport/master' into develop and more updates for #2
shbatm Dec 21, 2018
8d35f8e
Add SHOW/HIDE/TOGGLE ALL option to fix Jopyth/MMM-Remote-Control#101
shbatm Dec 21, 2018
f675a1a
Update to installer.sh
shbatm Dec 21, 2018
43ff75c
Missed a few new items.
shbatm Dec 21, 2018
3378b0d
Better API Guessing method, does not include socket notifications
shbatm Dec 21, 2018
84a8e1f
Add Electron functions to Power Menu and fix error response
shbatm Dec 21, 2018
6dd6378
Added Delayed Function Calls
shbatm Dec 22, 2018
b4aeb42
Added ability to create custom menu items (addresses #97 & #94)
shbatm Dec 23, 2018
fef3b4e
Added dynamic Module Control menu (automatically includes #97)
shbatm Dec 24, 2018
2682f49
Fix for external API registration
shbatm Jan 1, 2019
4a0a3fc
Fix for apiKey in installer.sh
shbatm Jan 1, 2019
5c3e273
Only turn on monitor if it's off.
shbatm Jan 1, 2019
b5d6ff1
Remove debugging console calls.
shbatm Jan 1, 2019
5c2fd87
Add option to send a formatted name for each API action (for menu list)
shbatm Jan 1, 2019
a6395df
Minor bugfix in Remote UI
shbatm Jan 3, 2019
560f004
Fix Jopyth/MMM-Remote-Control#87 - Unhandled Error
shbatm Jan 4, 2019
d765480
Improvements to regex for external API
shbatm Jan 4, 2019
8512656
Fix checkDelay error on API monitor call
shbatm Jan 5, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ node_modules

# Default settings
settings.json

# Package Lock File
package-lock.json

210 changes: 210 additions & 0 deletions API/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
## MagicMirror Remote Control API

## Introduction

The MMM-Remote-Control Module for MagicMirror² implements a RESTful(-ish) API to control the Magic Mirror using the existing functionality built-in to MMM-Remote-Control, as well as the notifications commands built into most modules. In addition, the API creates a basic framework which allows for each module to expand or customize their own API by a simple notificiation.

This expansion was developed by [shbatm](https://github.com/shbatm) using [juzim's MMM-Api](https://github.com/juzim/MMM-Api) and of-course, [jopyth's MMM-Remote-Control](https://github.com/jopyth/MMM-Remote-Control).

## Overview

This extension exposes the `/api` URL from your MagicMirror² installation. Just like using the regular MMM-Remote-Control module, make sure your configuration listens on more than just `localhost`.

All URLs will be of the form: `http://magicmirrorip:8080/api/{your command}` and depending on the command, either `GET` or `POST` methods are accepted.

### Basic examples for showing an Alert on the screen

```bash
$ curl -X GET http://magicmirrorip:8080/api/module/alert/showalert?message=Hello&timer=2000
```

```bash
$ curl -X POST http://magicmirrorip:8080/api/module/alert/showalert \
-H 'content-type: application/json' \
-d '{
"title": "Hello World!",
"message": "Alert Successfully Shown!",
"timer": 2000
}'
```

### Basic examples of sending a Module Notification

```bash
$ curl -X GET http://magicmirrorip:8080/api/notification/HELLO_WORLD
```

```bash
$ curl -X POST http://magicmirrorip:8080/api/notification/HELLO_WORLD \
-H 'content-type: application/json' \
-d '{
"mypayload": "Hello World!",
"somthingelse": "Wooo!"
}'
```

## Authentication

Providing an API key is recommended; however, remains optional. If you wish to use an API key to authenticate, add an `apiKey:` option to the config section for this module.

If you ran the `installer.sh` script when you installed the module, a non-canoical UUID is generated for you to use; you can use this unique code, or use any string you wish.

### Example Config Section
```js
{
module: 'MMM-Remote-Control'
config: {
apiKey: 'bc2e979db92f4741afad01d5d18eb8e2'
}
},
```

### Passing your API key

The API Key can be passed in one of two ways, either as part of the query string at the end of the URL:
```bash
$ curl -X GET http://magicmirrorip:8080/api/module/alert/showalert?message=Hello&timer=2000&apiKey=bc2e979db92f4741afad01d5d18eb8e2
```

It can also be passed as an Authentication Header:
```bash
$ curl -X POST http://magicmirrorip:8080/api/module/alert/showalert \
-H 'content-type: application/json' \
-H 'Authentication: apiKey bc2e979db92f4741afad01d5d18eb8e2' \
-d '{
"title": "Hello World!",
"message": "Alert Successfully Shown!",
"timer": 2000
}'
```

***For convenience, the remainder of the examples omit the API Key***

## Methods

There are three general categories of API commands:

**1. MMM-Remote-Control Internal Commands** -- these are used to call the existing commands that MMM-Remote-Control already exposes. For example, to turn off the monitor ("MONITOROFF"):

```bash
$ curl -X GET http://magicmirrorip:8080/api/monitor/off
```

**2. External APIs (Guessed)** -- when this module first loads, it parses all of the installed modules' source code and checks for any custom notifications that are used. From this basic search, it tries to "guess" notification actions that may be valid, without them being explicitly defined anywhere else. For example, the "alert" command examples above are not defined within this module, the 'alert' module just looks for a notification, "SHOW_ALERT"--this is exposed as a `/module/alert/showalert` action in the External API processor. Full credit to this idea goes to `juzim` from the MMM-Api module.

**3. External APIs (Explicit)** -- these commands are developed when a module loads and sends a "REGISTER_API" notification with command details to this module. These commands will overwrite any "guessed" commands and can provide a way for a module to define its own API, but still use the same routes already in place.

### 1. MMM-Remote-Control Internal Commands

The majority of MMM-Remote-Control's abilities are extended to the API (this is a fundamental reason for "extending" this module instead of creating a new one for the API).

[Review the API documentation on Postman here](https://documenter.getpostman.com/view/6167403/Rzfni66c)

The Postman [collection file](API/postman_collection.json) is also included in the repo if you want to load it and test calls on your machine.

### 2. External APIs (Guessed)

As discussed above, these methods are guessed based on your currently installed modules. To see what actions are available on your particular installation:

| Method | URL | Description |
| ------ | --- | ------- |
| GET | /api/module | Return a list of all external API actions registered.
| GET | /api/module/:moduleName | Returns registered API actions for a given module<br>`:moduleName`: Name or Identifier for an installed & activated module.

- *NOTE:* Just because an action appears in this list, does not necessarily mean it is valid and the related module will do what you want. Consult each modules' README for details on what notifications can be used and how.

#### Example:

```bash
$ curl -X GET http://magicmirrorip:8080/api/module/newsfeed
```

#### Returns:

```json
{
"success": true,
"module": "newsfeed",
"path": "newsfeed",
"actions": {
"newsitems": {
"notification": "NEWS_ITEMS"
},
"articlenext": {
"notification": "ARTICLE_NEXT"
},
"articleprevious": {
"notification": "ARTICLE_PREVIOUS"
},
"articlemoredetails": {
"notification": "ARTICLE_MORE_DETAILS"
},
"articlescrollup": {
"notification": "ARTICLE_SCROLL_UP"
},
"articlelessdetails": {
"notification": "ARTICLE_LESS_DETAILS"
},
"articletogglefull": {
"notification": "ARTICLE_TOGGLE_FULL"
}
},
"guessed": true
}
```

| Parameter | Description |
| :-: | -- |
| `"success"` | Result of the GET call
| `"module"` | Module name
| `"path"` | API path to use. All lower case, with "MMM-" and "-"s removed (e.g. MMM-Remote-Control's path if it had one would be `/api/module/remotecontrol/`). Can be customized for explicit External APIs.
| `"actions"` | The list of actions registered, along with the respective notifications that they will call.<br>For example, `GET /api/module/newsfeed/articlenext` will send a `"ARTICLE_NEXT"` notification to the `newsfeed` module
| `"guessed"` | Whether or not the API actions were guessed (not all are reliable) or if they were explicitly provided by the module.

### 3. External APIs (Explicit) - Extending Another Module with this API

For module developers, you can extend the API to accomodate your needs by sending a "REGISTER_API" module notification. Below is an example and details.

If correctly formated, any details sent here will override the "guessed" action by #2 above.

```js
let payload = {
module: this.name,
path: "modulename",
actions: {
actionName: {
method: "GET",
notification: "NOTIFICATION_TO_SEND",
payload: ObjectToSend,
prettyName: "Action Name"
},
anotherActionName: {
method: "POST",
notification: "NOTIFICATION_TO_SEND"
}
}
};
this.sendNotification("REGISTER_API", payload);
```

| Parameter | Description |
| :-: | - |
| `module` | Actual Name of your Module (e.g. "MMM-Your-Module-Name, or just use `this.name`)
| `path` | Path to use in the API (e.g. `path: "mymodulename"`) translates to `/api/module/mymodulename`
| `actions` | An `Object` defining the actions you want to expose. See below for details.
| `actionName` | The name for your action (e.g. called from `/api/module/mymodulename/actionName`).
| `method` | *Optional:* The HTTP Method to use.<br>Valid options are: `"GET"` or `"POST"`. If `method` is not provided in an action, then both `"GET"` or `"POST"` methods will be treated as valid.
| `notification` | The notification to send to your module. When the API receives a valid action, it passes a Module Notification to your module. It is your responsibility to do something with that notification to make the action work.
| `prettyName` | *Optional:* You can specify a Formatted Name to use in dynamic menus, like the MMM-Remote-Control Module Control menu, otherwise one will be guessed based on the Notification text.
| `payload` | *Optional:* If you always want the module to send the same `payload`, you can provide an `Object` here. It will be merged into the `payload` sent with the notification, which will also include:<br>1. URL Parameter, if used. See notes on `payload` Object below.<br>2. Query String, if used. API key will be removed.<br>3. Request body, if `POST` method is used and a body sent.<br>4. Finally, this parameter.

#### About the `payload` Object

Your module will be sent a `payload` with the notification, depending on the request details, and if you provided a `payload` Object to send. It is a merged object, containing one or more of the following inputs.

1. URL Parameter. (e.g. `/api/module/mymodulename/action/:p`, where `:p` is the parameter). If nothing else below is passed or provided, this will be returned as a string. If anything else below is sent, this will be provided at `payload.param` in the notification's `payload` Object.
2. Query String. Anything passed to the query string, except the API Key (if used) will be passed through `payload`. For example, `/api/module/mymodulename/action?param1=Something&param2=Else` will be passed in `payload` as `{ param1: "Something", param2: "Else" }`
3. `POST` Body. Same as query string above.
4. Custom Payload. Any `Object` provided with the `payload:` key when you send the initial "REGISTER_API" notification.

The response sent by the API will include the `payload` Object it sent to your module in the response body for debugging purposes.
Loading