mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-08 05:31:56 +00:00
Initial commit
This commit is contained in:
129
smartapps/vlaminck/alfred-workflow.src/alfred-workflow.groovy
Normal file
129
smartapps/vlaminck/alfred-workflow.src/alfred-workflow.groovy
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright 2015 SmartThings
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* Alfred Workflow
|
||||
*
|
||||
* Author: SmartThings
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "Alfred Workflow",
|
||||
namespace: "vlaminck",
|
||||
author: "SmartThings",
|
||||
description: "This SmartApp allows you to interact with the things in your physical graph through Alfred.",
|
||||
category: "Convenience",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/alfred-app.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/alfred-app@2x.png",
|
||||
oauth: [displayName: "SmartThings Alfred Workflow", displayLink: ""]
|
||||
)
|
||||
|
||||
preferences {
|
||||
section("Allow Alfred to Control These Things...") {
|
||||
input "switches", "capability.switch", title: "Which Switches?", multiple: true, required: false
|
||||
input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false
|
||||
}
|
||||
}
|
||||
|
||||
mappings {
|
||||
path("/switches") {
|
||||
action: [
|
||||
GET: "listSwitches",
|
||||
PUT: "updateSwitches"
|
||||
]
|
||||
}
|
||||
path("/switches/:id") {
|
||||
action: [
|
||||
GET: "showSwitch",
|
||||
PUT: "updateSwitch"
|
||||
]
|
||||
}
|
||||
path("/locks") {
|
||||
action: [
|
||||
GET: "listLocks",
|
||||
PUT: "updateLocks"
|
||||
]
|
||||
}
|
||||
path("/locks/:id") {
|
||||
action: [
|
||||
GET: "showLock",
|
||||
PUT: "updateLock"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {}
|
||||
|
||||
def updated() {}
|
||||
|
||||
def listSwitches() {
|
||||
switches.collect { device(it,"switch") }
|
||||
}
|
||||
void updateSwitches() {
|
||||
updateAll(switches)
|
||||
}
|
||||
def showSwitch() {
|
||||
show(switches, "switch")
|
||||
}
|
||||
void updateSwitch() {
|
||||
update(switches)
|
||||
}
|
||||
|
||||
def listLocks() {
|
||||
locks.collect { device(it, "lock") }
|
||||
}
|
||||
void updateLocks() {
|
||||
updateAll(locks)
|
||||
}
|
||||
def showLock() {
|
||||
show(locks, "lock")
|
||||
}
|
||||
void updateLock() {
|
||||
update(locks)
|
||||
}
|
||||
|
||||
private void updateAll(devices) {
|
||||
def command = request.JSON?.command
|
||||
if (command) {
|
||||
devices."$command"()
|
||||
}
|
||||
}
|
||||
|
||||
private void update(devices) {
|
||||
log.debug "update, request: ${request.JSON}, params: ${params}, devices: $devices.id"
|
||||
def command = request.JSON?.command
|
||||
if (command) {
|
||||
def device = devices.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
device."$command"()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private show(devices, name) {
|
||||
def device = devices.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
}
|
||||
else {
|
||||
def s = device.currentState(name)
|
||||
[id: device.id, label: device.displayName, name: device.displayName, state: s]
|
||||
}
|
||||
}
|
||||
|
||||
private device(it, name) {
|
||||
if (it) {
|
||||
def s = it.currentState(name)
|
||||
[id: it.id, label: it.displayName, name: it.displayName, state: s]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright 2015 SmartThings
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SmartClockChatSender
|
||||
*
|
||||
* Author: Steve Vlaminck
|
||||
*
|
||||
* Date: 2014-02-03
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "SmartBlock Chat Sender",
|
||||
namespace: "vlaminck/Minecraft",
|
||||
author: "SmartThings",
|
||||
description: "Send chat messages into Minecraft via the SmartBlock mod",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
|
||||
)
|
||||
|
||||
preferences {
|
||||
page(name: "chatPage", title: "Send Notifications Into Minecraft", install: true, uninstall: true) {
|
||||
section {
|
||||
input(name: "chatsEnabled", type: "bool", title: "Enable This Notification?", defaultValue: "true")
|
||||
input(name: "modes", type: "mode", title: "Notify SmartBlock users when the mode changes to:", description: "(optional)", multiple: true, required: false)
|
||||
input(name: "username", type: "string", title: "Only send to this username", required: false, description: "(optional)")
|
||||
input(name: "customMessage", type: "string", title: "Custom message?", required: false, description: "(optional)")
|
||||
}
|
||||
section(hidden: true, hideable: true, title: "Other Options") {
|
||||
label(title: "Label this Notification", required: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
log.debug "Installed with settings: ${settings}"
|
||||
|
||||
initialize()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "Updated with settings: ${settings}"
|
||||
|
||||
unsubscribe()
|
||||
initialize()
|
||||
}
|
||||
|
||||
def initialize() {
|
||||
subscribe(location, modeChangeHandler)
|
||||
}
|
||||
|
||||
def modeChangeHandler(evt) {
|
||||
def newMode = evt.value
|
||||
log.debug "evt: ${newMode}"
|
||||
if (modes && modes.contains(newMode))
|
||||
{
|
||||
def message = customMessage ?: "SmartThings mode has changed to: \"${newMode}\""
|
||||
chatMessageToMC(message)
|
||||
}
|
||||
}
|
||||
|
||||
def chatMessageToMC(message) {
|
||||
|
||||
def parent = app.getParent()
|
||||
|
||||
def url = "${parent.getServerURL()}/chat?message=${message.encodeAsURL()}"
|
||||
|
||||
if (username)
|
||||
{
|
||||
url += "&username=${username.encodeAsURL()}"
|
||||
}
|
||||
log.debug "POST to ${url}"
|
||||
|
||||
httpPost(url, "foo=bar") { response ->
|
||||
content = response.data
|
||||
log.debug "response: ${content}"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* Copyright 2015 SmartThings
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SmartBlock Linker
|
||||
*
|
||||
* Author: Steve Vlaminck
|
||||
*
|
||||
* Date: 2013-12-26
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "SmartBlock Linker",
|
||||
namespace: "vlaminck/Minecraft",
|
||||
author: "SmartThings",
|
||||
description: "A SmartApp that links SmartBlocks to switches",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
|
||||
)
|
||||
|
||||
preferences {
|
||||
|
||||
page(name: "linkerPage")
|
||||
}
|
||||
|
||||
def linkerPage(params) {
|
||||
|
||||
log.debug "linkerPage params: ${params}"
|
||||
|
||||
dynamicPage(name: "linkerPage", title: "Link your SmartBlock to a physical device", install: true, uninstall: false) {
|
||||
|
||||
section {
|
||||
input(
|
||||
name: "linkedSmartBlock",
|
||||
type: "capability.switch",
|
||||
// type: "device.SmartBlock",
|
||||
title: "Linked SmartBlock",
|
||||
required: true,
|
||||
multiple: false
|
||||
)
|
||||
input(
|
||||
name: "switchUpdatesBlock",
|
||||
type: "bool",
|
||||
title: "Update this SmartBlock when the switch below changes state",
|
||||
description: "",
|
||||
defaultValue: "false"
|
||||
)
|
||||
}
|
||||
section {
|
||||
input(
|
||||
name: "linkedSwitch",
|
||||
type: "capability.switch",
|
||||
title: "Linked Switch",
|
||||
required: true,
|
||||
multiple: false
|
||||
)
|
||||
input(
|
||||
name: "blockUpdatesSwitch",
|
||||
type: "bool",
|
||||
title: "Update this switch when the SmartBlock above changes state",
|
||||
description: "",
|
||||
defaultValue: "true"
|
||||
)
|
||||
}
|
||||
|
||||
section {
|
||||
label(
|
||||
title: "Label this Link",
|
||||
required: false
|
||||
)
|
||||
mode(
|
||||
title: "Only link these devices when in one of these modes",
|
||||
description: "All modes"
|
||||
)
|
||||
}
|
||||
|
||||
section("When \"Update this SmartBlock...\" is on") {
|
||||
paragraph "If you place a Redstone Lamp next to your SmartBlock, it will turn on/off when \"Linked Switch\" turns on/off"
|
||||
}
|
||||
|
||||
section("When \"Update this switch...\" is on") {
|
||||
paragraph "If you place a lever on your Minecraft SmartBlock, it will control \"Linked Switch\""
|
||||
}
|
||||
|
||||
section("Why turning both on can be bad") {
|
||||
paragraph "Because there can be latency."
|
||||
paragraph "Flipping the lever will send a signal from Minecraft to SmartThings. SmartThings will then send the signal back when the light has turned on."
|
||||
paragraph "If you flip the lever again before that round trip is complete, you can get into an infinite loop of signals being sent back and forth."
|
||||
paragraph "You've been warned ;)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
log.debug "Installed with settings: ${settings}"
|
||||
|
||||
initialize()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "Updated with settings: ${settings}"
|
||||
|
||||
unsubscribe()
|
||||
initialize()
|
||||
}
|
||||
|
||||
def initialize() {
|
||||
|
||||
if (blockUpdatesSwitch)
|
||||
{
|
||||
subscribe(linkedSmartBlock, "level", updateSwitchLevel)
|
||||
subscribe(linkedSmartBlock, "switch", updateSwitchState)
|
||||
}
|
||||
|
||||
if (switchUpdatesBlock)
|
||||
{
|
||||
subscribe(linkedSwitch, "level", updateBlockLevel)
|
||||
subscribe(linkedSwitch, "switch", updateBlockState)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def updateSwitchLevel(evt) {
|
||||
int level = evt.value as int
|
||||
log.debug "matching level: ${level}"
|
||||
linkedSwitch.setLevel(level)
|
||||
}
|
||||
|
||||
def updateBlockLevel(evt) {
|
||||
int level = evt.value as int
|
||||
log.debug "matching level: ${level}"
|
||||
linkedSmartBlock.setLevel(level)
|
||||
}
|
||||
|
||||
def updateSwitchState(evt) {
|
||||
log.debug "setting linkedSwitch to ${evt.value}"
|
||||
linkedSwitch."${evt.value}"()
|
||||
}
|
||||
|
||||
def updateBlockState(evt) {
|
||||
log.debug "setting linkedSmartBlock to ${evt.value}"
|
||||
linkedSmartBlock."${evt.value}"()
|
||||
}
|
||||
|
||||
def getBlockId() {
|
||||
return linkedSmartBlock.id
|
||||
}
|
||||
|
||||
def getLinkerDescription() {
|
||||
|
||||
def left = linkedSmartBlock ? "${linkedSmartBlock.label ?: linkedSmartBlock.name}" : ""
|
||||
def right = linkedSwitch ? "${linkedSwitch.label ?: linkedSwitch.name}" : ""
|
||||
|
||||
log.debug "left: ${left}, right: ${right}"
|
||||
|
||||
def leftLink = switchUpdatesBlock ? "<" : ""
|
||||
def rightLink = blockUpdatesSwitch ? ">" : ""
|
||||
|
||||
log.debug "leftLink: ${leftLink}, rightLink: ${rightLink}"
|
||||
|
||||
log.debug "switchUpdatesBlock: ${switchUpdatesBlock}"
|
||||
log.debug "blockUpdatesSwitch: ${blockUpdatesSwitch}"
|
||||
|
||||
if (leftLink == "" && rightLink == "")
|
||||
{
|
||||
return null
|
||||
}
|
||||
|
||||
"${left} ${leftLink}--${rightLink} ${right}"
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
/**
|
||||
* Copyright 2015 SmartThings
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
import com.sun.corba.se.spi.activation._ServerImplBase
|
||||
|
||||
/**
|
||||
* SmartBlock Manager
|
||||
*
|
||||
* Author: Steve Vlaminck
|
||||
*
|
||||
* Date: 2013-12-24
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "SmartBlock Manager",
|
||||
namespace: "vlaminck/Minecraft",
|
||||
author: "SmartThings",
|
||||
description: "A SmartApp for managing SmartBlocks",
|
||||
iconUrl: "http://f.cl.ly/items/0p2c222z0p2K0y3y3w2M/SmartApp-icon.png",
|
||||
iconX2Url: "http://f.cl.ly/items/0p2c222z0p2K0y3y3w2M/SmartApp-icon.png",
|
||||
oauth: [displayName: "SmartBlock Manager", displayLink: ""]
|
||||
)
|
||||
|
||||
preferences {
|
||||
|
||||
page(name: "listPage")
|
||||
page(name: "serverPage")
|
||||
page(name: "blockPage")
|
||||
page(name: "linkerPage")
|
||||
page(name: "notifierPage")
|
||||
page(name: "chatPage")
|
||||
|
||||
section("SmartBlock Manager") {
|
||||
input name: "explanation1", title: "Every time you place a SmartBlock in Minecraft, a new SmartThings Device will be created. These Devices can be used in various SmartApps like \"Minecraft Notifier\", or \"Switch State Matcher\"", description: "", type: "paragraph", element: "paragraph", required: false
|
||||
input name: "explanation2", title: "In order for SmartThings to send commands back to your Minecraft SmartBlocks, you will have to enter your Server Address via the SmartThings iOS or Android app", description: "", type: "paragraph", element: "paragraph", required: false
|
||||
}
|
||||
}
|
||||
|
||||
def listPage() {
|
||||
|
||||
log.debug "listPage"
|
||||
|
||||
def linkerApps = findAllChildAppsByName("SmartBlock Linker")
|
||||
def linkerState = linkerApps ? "complete" : ""
|
||||
def linkerDescription = linkerApps.collect { it.label ?: it.name }.sort().join("\n")
|
||||
|
||||
def notifierApps = findAllChildAppsByName("SmartBlock Notifier")
|
||||
def notifierState = notifierApps ? "complete" : ""
|
||||
def notifierDescription = notifierApps.collect { it.label ?: it.name }.sort().join("\n")
|
||||
|
||||
def chatApps = findAllChildAppsByName("SmartBlock Chat Sender")
|
||||
def chatState = chatApps ? "complete" : ""
|
||||
def chatDescription = chatApps.collect { it.label ?: it.name }.sort().join("\n")
|
||||
|
||||
return dynamicPage(name: "listPage", title: "Configure Your SmartBlocks", install: true, uninstall: true) {
|
||||
section {
|
||||
href(
|
||||
name: "toLinkerPage",
|
||||
title: "Link SmartBlocks To Switches",
|
||||
description: linkerDescription,
|
||||
page: "linkerPage",
|
||||
state: linkerState
|
||||
)
|
||||
href(
|
||||
name: "toNotifierPage",
|
||||
title: "Get Notified When a SmartBlock updates",
|
||||
description: notifierDescription,
|
||||
page: "notifierPage",
|
||||
state: notifierState
|
||||
)
|
||||
href(
|
||||
name: "toChatPage",
|
||||
title: "Send Notifications into Minecraft",
|
||||
description: chatDescription,
|
||||
page: "chatPage",
|
||||
state: chatState
|
||||
)
|
||||
}
|
||||
|
||||
section {
|
||||
input(
|
||||
name: "serverIp",
|
||||
title: "In order for SmartThings to send commands back to the SmartBlocks on your Minecraft server, you will have to enter your Server Address",
|
||||
type: "text",
|
||||
required: false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def serverPage() {
|
||||
log.debug "serverPage"
|
||||
dynamicPage(name: "serverPage", title: "Connect SmartThings To Your Minecraft Server") {
|
||||
section {
|
||||
input(
|
||||
name: "serverIp",
|
||||
title: "In order for SmartThings to send commands back to the SmartBlocks on your Minecraft server, you will have to enter your Server Address",
|
||||
type: "text",
|
||||
required: false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def linkerPage() {
|
||||
dynamicPage(name: "linkerPage", title: "Link SmartBlocks To Switches") {
|
||||
section {
|
||||
app(
|
||||
title: "Link a SmartBlock to a switch",
|
||||
name: "blockLinker-new",
|
||||
namespace: "vlaminck/Minecraft",
|
||||
appName: "SmartBlock Linker",
|
||||
page: "linkerPage",
|
||||
multiple: true,
|
||||
params: ["blocks": getChildDevices()]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def notifierPage() {
|
||||
return dynamicPage(name: "notifierPage", title: "Get Notified When a SmartBlock is updated") {
|
||||
section {
|
||||
app(
|
||||
title: "Get Notified",
|
||||
name: "blockNotifier-new",
|
||||
namespace: "vlaminck/Minecraft",
|
||||
appName: "SmartBlock Notifier",
|
||||
multiple: true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def chatPage() {
|
||||
return dynamicPage(name: "chatPage", title: "Send Notifications into Minecraft") {
|
||||
section {
|
||||
app(
|
||||
title: "Send Notifications",
|
||||
name: "chatSender-new",
|
||||
namespace: "vlaminck/Minecraft",
|
||||
appName: "SmartBlock Chat Sender",
|
||||
multiple: true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mappings {
|
||||
path("/block") { // any need for GET?
|
||||
action:
|
||||
[
|
||||
POST : "createBlock",
|
||||
PUT : "updateBlock",
|
||||
DELETE: "deleteBlock"
|
||||
]
|
||||
}
|
||||
path("/ack") {
|
||||
action:
|
||||
[
|
||||
POST: "ack"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
def createBlock() {
|
||||
def data = request.JSON
|
||||
def blockCoordinates = blockCoordinates(data)
|
||||
def blockDNI = blockDNI(data)
|
||||
def block = block(data)
|
||||
|
||||
if (block) {
|
||||
log.debug "Block ${block?.label} with id $blockDNI already exists"
|
||||
} else {
|
||||
block = addChildDevice("vlaminck/Minecraft", "Smart Block", blockDNI, null, [name: "SmartBlock", label: "SmartBlock $blockCoordinates"])
|
||||
}
|
||||
|
||||
block?.setCoordinates(data.x, data.y, data.z)
|
||||
block?.setDestroyed(false)
|
||||
block?.setWorldSeed(data?.worldSeed)
|
||||
block?.setDimensionName(data?.dimensionName)
|
||||
block?.setPlacedBy(data?.placedBy)
|
||||
|
||||
if (serverIp) {
|
||||
block.setServerIp(serverIp)
|
||||
}
|
||||
|
||||
log.debug "created ${block?.label} with id $blockDNI"
|
||||
}
|
||||
|
||||
def ack() {
|
||||
log.debug "ack params : $params"
|
||||
log.debug "ack JSON : ${request.JSON}"
|
||||
|
||||
sendDataToBlock(request?.JSON, false)
|
||||
}
|
||||
|
||||
def updateBlock() {
|
||||
sendDataToBlock(request?.JSON, true)
|
||||
}
|
||||
|
||||
def sendDataToBlock(data, isStateChange) {
|
||||
|
||||
def blockCoordinates = blockCoordinates(data)
|
||||
def blockDNI = blockDNI(data)
|
||||
def block = block(data)
|
||||
log.debug "updating Block ${block?.label} with id $blockDNI"
|
||||
|
||||
block?.neighborBlockChange(data)
|
||||
|
||||
if (data.worldSeed) {
|
||||
block.setWorldSeed(data.worldSeed)
|
||||
}
|
||||
|
||||
if (data.dimensionName) {
|
||||
block.setDimensionName(data.dimensionName)
|
||||
}
|
||||
|
||||
if (data.placedBy) {
|
||||
block.setPlacedBy(data.placedBy)
|
||||
}
|
||||
|
||||
block.setServerIp(serverIp)
|
||||
|
||||
}
|
||||
|
||||
def deleteBlock() {
|
||||
def data = request.JSON
|
||||
def blockDNI = blockDNI(data)
|
||||
def block = block(data)
|
||||
|
||||
block?.setDestroyed(true)
|
||||
|
||||
|
||||
|
||||
log.debug "attempting to delete Block ${block?.label} with id $blockDNI"
|
||||
deleteChildDevice(blockDNI)
|
||||
}
|
||||
|
||||
private blockCoordinates(data) {
|
||||
return "(${data?.x},${data?.y},${data?.z})"
|
||||
}
|
||||
|
||||
private blockDNI(data) {
|
||||
"${data.worldSeed}|${data.dimensionName}|${blockCoordinates(data)}".encodeAsMD5()
|
||||
}
|
||||
|
||||
private block(data) {
|
||||
return getChildDevice(blockDNI(data))
|
||||
}
|
||||
|
||||
def installed() {
|
||||
log.debug "Installed with settings: ${settings}"
|
||||
|
||||
initialize()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "Updated with settings: ${settings}"
|
||||
|
||||
unsubscribe()
|
||||
initialize()
|
||||
}
|
||||
|
||||
def initialize() {
|
||||
// update all children with serverIp.
|
||||
if (serverIp) {
|
||||
getChildDevices().each { block ->
|
||||
block.setServerIp(serverIp)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public getServerURL() {
|
||||
return "http://${serverIp}:3333"
|
||||
}
|
||||
@@ -0,0 +1,989 @@
|
||||
/**
|
||||
* Copyright 2015 SmartThings
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SmartBlock Notifier
|
||||
*
|
||||
* Author: Steve Vlaminck
|
||||
*
|
||||
* Date: 2013-12-27
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "SmartBlock Notifier",
|
||||
namespace: "vlaminck/Minecraft",
|
||||
author: "SmartThings",
|
||||
description: "A SmartApp that notifies you when things are happening around your SmartBlocks",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
|
||||
)
|
||||
|
||||
preferences {
|
||||
page(name: "firstPage")
|
||||
page(name: "redstonePage")
|
||||
page(name: "neighborBlockPage")
|
||||
page(name: "messageBuilderPage")
|
||||
page(name: "destroyedPage")
|
||||
}
|
||||
|
||||
def firstPage() {
|
||||
|
||||
def defaultLabelValue = smartBlock ? (smartBlock.label ?: smartBlock.name) : null
|
||||
|
||||
|
||||
def destroyedPageName = "destroyedPage"
|
||||
def destroyedComplete = pageStateComplete(destroyedPageName)
|
||||
def destroyedState = destroyedComplete ? "complete" : null
|
||||
def destroyedDescription = destroyedComplete ? messageDescriptionForPage(destroyedPageName) : null
|
||||
|
||||
def redstonePageName = "redstonePage"
|
||||
def redstoneComplete = pageStateComplete(redstonePageName)
|
||||
def redstoneState = redstoneComplete ? "complete" : null
|
||||
def redstoneDescription = redstoneComplete ? messageDescriptionForPage(redstonePageName) : null
|
||||
|
||||
def neighborPageName = "neighborBlockPage"
|
||||
def neighborComplete = pageStateComplete(neighborPageName)
|
||||
def neighborState = neighborComplete ? "complete" : null
|
||||
def neighborDescription = neighborComplete ? messageDescriptionForPage(neighborPageNamePageName) : null
|
||||
|
||||
dynamicPage(name: "firstPage", title: "Setup your notifications", install: true, uninstall: true) {
|
||||
|
||||
section("Get notifications for this SmartBlock") {
|
||||
input(name: "smartBlock", type: "capability.switch", title: "Which SmartBlock would you like to monitor?", multiple: false)
|
||||
// TODO: type: "device.smartBlock",
|
||||
}
|
||||
|
||||
section("Why would you like to be notified?") {
|
||||
href(name: "toDestroyedPage", page: destroyedPageName, title: "Because it was destroyed", description: destroyedDescription, state: destroyedState)
|
||||
|
||||
href(name: "toRedstonePage", page: redstonePageName, title: "Because its redstone signal changed", description: redstoneDescription, state: redstoneState)
|
||||
href(name: "toNeighborPage", page: neighborPageName, title: "Because a block next to it changed", description: neighborDescription, state: neighborState)
|
||||
}
|
||||
|
||||
section("Other Options") {
|
||||
label(title: "Label this notification", description: app.name, required: false, defaultValue: defaultLabelValue)
|
||||
mode(title: "Only send notifications when in one of these modes", description: "All modes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def destroyedPage() {
|
||||
def pageName = "destroyedPage"
|
||||
dynamicPage(name: pageName, title: "For when your block is destroyed") {
|
||||
smartPhoneNotificationSection(pageName)
|
||||
chatSection(pageName)
|
||||
messageBuilderSection(pageName)
|
||||
chatClosestPlayerSection(pageName)
|
||||
}
|
||||
}
|
||||
|
||||
def redstonePage() {
|
||||
def pageName = "redstonePage"
|
||||
dynamicPage(name: pageName, title: "Get Notified For Redstone Changes") {
|
||||
section("When Redstone Is") {
|
||||
input(name: "redstoneGreaterThan", type: "enum", required: false, title: "Greater Than", options: (0..15).collect {
|
||||
"${it}"
|
||||
})
|
||||
input(name: "redstoneLessThan", type: "enum", required: false, title: "Less than", options: (0..15).collect {
|
||||
"${it}"
|
||||
})
|
||||
input(name: "redstoneEqualTo", type: "enum", required: false, title: "Equal to", options: (0..15).collect {
|
||||
"${it}"
|
||||
})
|
||||
}
|
||||
smartPhoneNotificationSection(pageName)
|
||||
chatSection(pageName)
|
||||
messageBuilderSection(pageName)
|
||||
}
|
||||
}
|
||||
|
||||
def neighborBlockPage() {
|
||||
def pageName = "neighborBlockPage"
|
||||
dynamicPage(name: pageName, title: "Get Notified When a neighbor block updates") {
|
||||
section("Not all blocks send updates, but Chests definitely do") {
|
||||
input(type: "enum", name: "neighborBlockParsed", title: "When any of these blocks are updated", required: false, multiple: true, options: allBlocksParsed())
|
||||
}
|
||||
|
||||
smartPhoneNotificationSection(pageName)
|
||||
chatSection(pageName)
|
||||
messageBuilderSection(pageName)
|
||||
chatClosestPlayerSection(pageName)
|
||||
|
||||
section(title: "More Info", hideable: true, hidden: true) {
|
||||
href(name: "allIds", title: "A full list of blocks and items can be found here", url: "http://minecraft.gamepedia.com/Ids", style: "external", description: null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def messageBuilderPage(params) {
|
||||
|
||||
def pageName = params.pageName
|
||||
def size = messageBuilderOptions().size() * 2
|
||||
|
||||
dynamicPage(name: "messageBuilderPage", title: "Build your message") {
|
||||
section("These will be combined to form the final message.") {
|
||||
(0..size).each {
|
||||
input(
|
||||
name: "${pageName}MessagePart${it}",
|
||||
type: (it % 2) ? "enum" : "text",
|
||||
defaultValue: messagePartDefaultValue(pageName, it),
|
||||
options: (it % 2) ? messageBuilderOptions() : null,
|
||||
title: null, description: null, required: false, multiple: false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def smartPhoneNotificationSection(pageName) {
|
||||
section("SmartPhone notifications") {
|
||||
input("recipients", "contact", title: "Send notifications to") {
|
||||
input(name: "${pageName}WantsPush", title: "Push Notification", description: null, type: "bool", required: false, defaultValue: "false")
|
||||
input(name: "${pageName}WantsSms", title: "Text Message", description: "phone number", type: "phone", required: false)
|
||||
}
|
||||
input(name: "${pageName}WantsHH", title: "Hello Home only", description: null, type: "bool", required: false)
|
||||
}
|
||||
}
|
||||
|
||||
def chatSection(pageName) {
|
||||
section("Minecraft Chat Message") {
|
||||
input(name: "${pageName}ChatAllUsers", title: "Chat all users", type: "bool", required: false)
|
||||
input(name: "${pageName}ChatUsername", title: "Or chat to a specific username", type: "text", required: false)
|
||||
}
|
||||
}
|
||||
|
||||
def messageBuilderSection(pageName) {
|
||||
section("What should your message say?") {
|
||||
messageBuilderHref(pageName)
|
||||
}
|
||||
}
|
||||
|
||||
def messageBuilderHref(pageName) {
|
||||
def partsAreSet = messagePartsSet(pageName)
|
||||
def messageState = partsAreSet ? "complete" : ""
|
||||
def messageDescription = partsAreSet ? messageDescriptionForPage(pageName) : defaultMessageDescription(pageName)
|
||||
|
||||
href(
|
||||
name: "toBuilder",
|
||||
page: "messageBuilderPage",
|
||||
title: null,
|
||||
description: messageDescription ?: "Construct your message",
|
||||
state: messageState,
|
||||
params: [pageName: pageName]
|
||||
)
|
||||
}
|
||||
|
||||
def chatClosestPlayerSection(pageName) {
|
||||
section("Chat the closest player to the block. (usually the player that destroyed it)") {
|
||||
messageBuilderHref("${pageName}ClosestPlayer")
|
||||
}
|
||||
}
|
||||
|
||||
def pageStateComplete(pageName) {
|
||||
|
||||
if (pageName == "redstonePage") {
|
||||
if (redstoneGreaterThan) return true
|
||||
if (redstoneLessThan) return true
|
||||
if (redstoneEqualTo) return true
|
||||
return false
|
||||
}
|
||||
|
||||
if (pageName == "neighborBlockPage") {
|
||||
if (neighborBlockParsed) return true
|
||||
return false
|
||||
}
|
||||
|
||||
if (app."${pageName}WantsPush") return true
|
||||
if (app."${pageName}WantsSms") return true
|
||||
if (app."${pageName}WantsHH") return true
|
||||
if (app."${pageName}ChatAllUsers") return true
|
||||
if (app."${pageName}ChatUsername") return true
|
||||
if (app."${pageName}ClosestPlayer") return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
* INITIALIZE
|
||||
*/
|
||||
|
||||
def installed() {
|
||||
log.debug "Installed with settings: ${settings}"
|
||||
|
||||
initialize()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "Updated with settings: ${settings}"
|
||||
|
||||
unsubscribe()
|
||||
initialize()
|
||||
}
|
||||
|
||||
def initialize() {
|
||||
log.debug "initializing"
|
||||
subscribe(smartBlock, "redstoneSignalStrength", redstoneSignalStrengthHandler)
|
||||
subscribe(smartBlock, "smartBlockNeighborChanged", smartBlockNeighborChangedHandler, [filterEvents: false])
|
||||
subscribe(smartBlock, "smartBlockNeighborChanged", smartBlockNeighborChangedHandler, [filterEvents: false])
|
||||
subscribe(smartBlock, "blockDestroyed.true", smartBlockDestroyedHandler, [filterEvents: false])
|
||||
}
|
||||
|
||||
/*
|
||||
* EVENT HANDLERS
|
||||
*/
|
||||
|
||||
def smartBlockDestroyedHandler(evt) {
|
||||
log.debug "smartBlockDestroyedHandler evt.value: ${evt.value}"
|
||||
|
||||
def pageName = "destroyedPage"
|
||||
def message = message(pageName)
|
||||
notifyUser(pageName, message)
|
||||
}
|
||||
|
||||
def smartBlockNeighborChangedHandler(evt) {
|
||||
log.debug "smartBlockNeighborChangedHandler evt.value: ${evt.value}"
|
||||
log.debug "neighborBlockParsed: ${neighborBlockParsed}"
|
||||
|
||||
if (neighborBlockParsed?.contains(evt.value)) {
|
||||
notifyUserOfNeighborChange(evt.value)
|
||||
}
|
||||
}
|
||||
|
||||
def redstoneSignalStrengthHandler(evt) {
|
||||
log.debug "redstoneSignalStrengthHandler: ${evt.value}"
|
||||
|
||||
int newValue = evt.value as int
|
||||
int lastValue = smartBlock.latestState("redstoneSignalStrength").value as int
|
||||
|
||||
if (redstoneGreaterThan) {
|
||||
int gt = redstoneGreaterThan as int
|
||||
// log.debug "$newValue > $gt"
|
||||
if (newValue > gt) {
|
||||
log.debug "greater than ${gt}. send notification"
|
||||
notifyUserOfRedstoneChange(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
if (redstoneLessThan) {
|
||||
int lt = redstoneLessThan as int
|
||||
// log.debug "$newValue < $lt"
|
||||
if (newValue < lt) {
|
||||
log.debug "less than ${lt}. send notification"
|
||||
notifyUserOfRedstoneChange(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
if (redstoneEqualTo) {
|
||||
int et = redstoneEqualTo as int
|
||||
// log.debug "$newValue == $et"
|
||||
if (newValue == et) {
|
||||
log.debug "equal to ${et}. send notification"
|
||||
notifyUserOfRedstoneChange(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTIFICATIONS
|
||||
*/
|
||||
|
||||
def notifyUserOfRedstoneChange(value) {
|
||||
def msg = message("redstonePage")
|
||||
log.debug "message: ${msg}"
|
||||
def notificationMessage = msg ?: "${smartBlock} redstone signal is ${value}"
|
||||
notifyUser(notificationMessage)
|
||||
}
|
||||
|
||||
def notifyUserOfNeighborChange(value) {
|
||||
def msg = message("neighborPage")
|
||||
log.debug "message: ${msg}"
|
||||
def notificationMessage = msg ?: "${smartBlock} was updated by ${value}"
|
||||
notifyUser(notificationMessage)
|
||||
}
|
||||
|
||||
def notifyUser(pageName, messageToSend) {
|
||||
log.debug "notifyUser pageName: ${pageName}"
|
||||
|
||||
def closestPlayerMessage = message("${pageName}ClosestPlayer")
|
||||
log.debug "closestPlayerMessage = ${closestPlayerMessage}"
|
||||
def latestClosePlayer = getLatestClosePlayer()
|
||||
log.debug "latestClosePlayer = ${latestClosePlayer}"
|
||||
if (closestPlayerMessage && latestClosePlayer != "unknown") {
|
||||
log.debug "chatting closestPlayer"
|
||||
chatMessageToMC(closestPlayerMessage, latestClosePlayer)
|
||||
}
|
||||
|
||||
|
||||
def wantsHH = app."${pageName}WantsHH"
|
||||
log.debug "wantsHH = ${wantsHH}"
|
||||
if (wantsHH) {
|
||||
|
||||
log.debug "sending HH"
|
||||
sendNotificationEvent(messageToSend)
|
||||
|
||||
} else {
|
||||
if (location.contactBookEnabled) {
|
||||
sendNotificationToContacts(messageToSend, recipients)
|
||||
}
|
||||
else {
|
||||
|
||||
def wantsPush = app."${pageName}WantsPush"
|
||||
log.debug "wantsPush = ${wantsPush}"
|
||||
if (wantsPush && wantsPush != "false") {
|
||||
log.debug "sending push"
|
||||
sendPush(messageToSend)
|
||||
}
|
||||
|
||||
def wantsSms = app."${pageName}WantsSms"
|
||||
log.debug "wantsSms = ${wantsSms}"
|
||||
if (wantsSms) {
|
||||
log.debug "sending sms to: ${wantsSms}"
|
||||
sendSms(wantsSms, messageToSend)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def username = app."${pageName}ChatUsername"
|
||||
def allUsers = app."${pageName}ChatAllUsers"
|
||||
|
||||
log.debug "username = ${username}"
|
||||
log.debug "allUsers = ${allUsers}"
|
||||
|
||||
if (username && username != "") {
|
||||
log.debug "chatting username: ${username}"
|
||||
chatMessageToMC(messageToSend, username)
|
||||
} else if (allUsers) {
|
||||
log.debug "chatting all users"
|
||||
chatMessageToMC(messageToSend, null)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def chatMessageToMC(message, username) {
|
||||
log.debug "chatMessageToMC"
|
||||
|
||||
def url = "${app.getParent().getServerURL()}/chat?message=${message.encodeAsURL()}"
|
||||
if (username) {
|
||||
url = "${url}&username=${username.encodeAsURL()}"
|
||||
}
|
||||
|
||||
log.debug "POST to ${url}"
|
||||
|
||||
httpPost(url, "foo=bar") {}
|
||||
}
|
||||
|
||||
def messageDescriptionPartsForPage(pageName) {
|
||||
def size = messageBuilderOptions().size() * 2
|
||||
(0..size).collect { app."${pageName}MessagePart${it}" }
|
||||
}
|
||||
|
||||
def messagePartsSet(pageName) { // are any set?
|
||||
messageDescriptionPartsForPage(pageName).collect { !it }.unique().contains(false)
|
||||
}
|
||||
|
||||
def defaultMessageDescription(pageName) {
|
||||
def description = ""
|
||||
|
||||
if (pageName == "destroyedPage" || pageName == "redstonePage" || pageName == "neighborBlockPage") {
|
||||
def second = messageBuilderOptions()[messagePartDefaultValue(pageName, 1)]
|
||||
if (second) description = "\${${second}}"
|
||||
|
||||
def third = messagePartDefaultValue(pageName, 2)
|
||||
if (third) description = "${description} ${third}"
|
||||
|
||||
def fourth = messageBuilderOptions()[messagePartDefaultValue(pageName, 3)]
|
||||
if (fourth) description = "${description} \${${fourth}}"
|
||||
}
|
||||
|
||||
return description
|
||||
}
|
||||
|
||||
def messageDescriptionForPage(pageName) {
|
||||
|
||||
def parts = messageDescriptionPartsForPage(pageName)
|
||||
def messageParts = []
|
||||
parts.eachWithIndex { part, idx ->
|
||||
if (part != null && part != "null") {
|
||||
if (idx % 2) {
|
||||
messageParts << "\${${messageBuilderOptions()[part]}}"
|
||||
} else {
|
||||
messageParts << part
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (messageParts) {
|
||||
return messageParts.join(" ").trim()
|
||||
} else {
|
||||
return defaultMessageDescription()
|
||||
}
|
||||
}
|
||||
|
||||
def messagePartDefaultValue(pageName, part) {
|
||||
if (pageName == "destroyedPage") {
|
||||
if (part == 1) return "name"
|
||||
if (part == 2) return "was destroyed by"
|
||||
if (part == 3) return "closestPlayer"
|
||||
}
|
||||
|
||||
if (pageName == "neighborBlockPage") {
|
||||
if (part == 1) return "name"
|
||||
if (part == 2) return "has a redstone signal of"
|
||||
if (part == 3) return "redstoneSignalStrength"
|
||||
}
|
||||
|
||||
if (pageName == "redstonePage") {
|
||||
if (part == 1) return "name"
|
||||
if (part == 2) return "was updated by"
|
||||
if (part == 3) return "closestPlayer"
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
def message(pageName) {
|
||||
log.debug "building message"
|
||||
def messageParts = []
|
||||
|
||||
messageDescriptionPartsForPage(pageName).eachWithIndex { part, idx ->
|
||||
if (idx % 2) {
|
||||
// def option = messageBuilderOptions()[part]
|
||||
def optionPart = getMessagePartFromOption(part)
|
||||
if (optionPart) messageParts << optionPart
|
||||
} else {
|
||||
if (part) messageParts << part
|
||||
}
|
||||
}
|
||||
|
||||
def message = messageParts.join(" ").trim()
|
||||
log.debug "message: ${message}"
|
||||
return message
|
||||
}
|
||||
|
||||
def messageBuilderOptions() {
|
||||
return [
|
||||
"name": "SmartBlock name",
|
||||
"neighborBlockName": "Neighbor block name",
|
||||
"blockDestroyed": "Destroyed State ('destroyed' / 'OK')",
|
||||
"redstoneSignalStrength": "Redstone signal strength",
|
||||
"worldSeed": "World seed",
|
||||
"dimensionName": "Dimension name (World, Nether, End)",
|
||||
"coordinates": "Block coordinates",
|
||||
"closestPlayer": "Username of Closest player (within the past minute)",
|
||||
"placedBy": "Username of who placed the block"
|
||||
]
|
||||
}
|
||||
|
||||
def getMessagePartFromOption(optionKey) {
|
||||
log.debug "optionKey: ${optionKey}"
|
||||
if (optionKey == "name") return smartBlock.label ?: smartBlock.name
|
||||
if (optionKey == "closestPlayer") return getLatestClosePlayer()
|
||||
if (optionKey == "blockDestroyed") return smartBlock.latestValue("blockDestroyed") ? "OK" : "destroyed"
|
||||
return smartBlock.latestValue(optionKey)
|
||||
}
|
||||
|
||||
def getLatestClosePlayer() {
|
||||
def now = new Date()
|
||||
def minusOne = new Date(minutes: now.minutes - 1)
|
||||
def latestStates = smartBlock.statesSince("closestPlayer", minusOne)
|
||||
if (latestStates.size) {
|
||||
return latestStates[0].value
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
/*
|
||||
* BLOCKS
|
||||
*/
|
||||
|
||||
def settingsAsIds() {
|
||||
log.debug "settingsAsIds"
|
||||
log.debug "neighborBlockParsed: $neighborBlockParsed"
|
||||
|
||||
def subscribedIds = []
|
||||
|
||||
neighborBlockParsed.each {
|
||||
subscribedIds << convertBlockSettingToBlockId(it)
|
||||
}
|
||||
|
||||
return subscribedIds
|
||||
}
|
||||
|
||||
def convertBlockSettingToBlockId(setting) {
|
||||
def id = setting.substring(0, setting.indexOf(" "))
|
||||
def name = allBlocks()[id]
|
||||
log.debug "id: $id, name:${name}"
|
||||
return id
|
||||
}
|
||||
|
||||
def allBlocksParsed() {
|
||||
allBlocks().collect { k, v -> "${k} ${v}" }
|
||||
}
|
||||
|
||||
def allBlocks() {
|
||||
[
|
||||
"0": "Air",
|
||||
"1": "Stone",
|
||||
"2": "Grass",
|
||||
"3": "Dirt",
|
||||
"4": "Cobblestone",
|
||||
"5": "Oak Wood Plank",
|
||||
"5:1": "Spruce Wood Plank",
|
||||
"5:2": "Birch Wood Plank",
|
||||
"5:3": "Jungle Wood Plank",
|
||||
"6": "Oak Sapling",
|
||||
"6:1": "Spruce Sapling",
|
||||
"6:2": "Birch Sapling",
|
||||
"6:3": "Jungle Sapling",
|
||||
"7": "Bedrock",
|
||||
"8": "Water",
|
||||
"9": "Stationary Water",
|
||||
"10": "Lava",
|
||||
"11": "Stationary Lava",
|
||||
"12": "Sand",
|
||||
"13": "Gravel",
|
||||
"14": "Gold Ore",
|
||||
"15": "Iron Ore",
|
||||
"16": "Coal Ore",
|
||||
"17": "Oak Wood",
|
||||
"17:1": "Spruce Wood",
|
||||
"17:2": "Birch Wood",
|
||||
"17:3": "Jungle Wood",
|
||||
"18": "Oak Leaves",
|
||||
"18:1": "Spruce Leaves",
|
||||
"18:2": "Birch Leaves",
|
||||
"18:3": "Jungle Leaves",
|
||||
"19": "Sponge",
|
||||
"20": "Glass",
|
||||
"21": "Lapis Lazuli Ore",
|
||||
"22": "Lapis Lazuli Block",
|
||||
"23": "Dispenser",
|
||||
"24": "Sandstone",
|
||||
"24:1": "Chiseled Sandstone",
|
||||
"24:2": "Smooth Sandstone",
|
||||
"25": "Note Block",
|
||||
"26": "Bed Block",
|
||||
"27": "Powered Rail",
|
||||
"28": "Detector Rail",
|
||||
"29": "Sticky Piston",
|
||||
"30": "Web",
|
||||
"31": "Dead Shrub",
|
||||
"31:1": "Grass",
|
||||
"31:2": "Fern",
|
||||
"32": "Dead Shrub",
|
||||
"33": "Piston",
|
||||
"34": "Piston Head",
|
||||
"35": "White Wool",
|
||||
"35:1": "Orange Wool",
|
||||
"35:2": "Magenta Wool",
|
||||
"35:3": "Light Blue Wool",
|
||||
"35:4": "Yellow Wool",
|
||||
"35:5": "Lime Wool",
|
||||
"35:6": "Pink Wool",
|
||||
"35:7": "Gray Wool",
|
||||
"35:8": "Light Gray Wool",
|
||||
"35:9": "Cyan Wool",
|
||||
"35:10": "Purple Wool",
|
||||
"35:11": "Blue Wool",
|
||||
"35:12": "Brown Wool",
|
||||
"35:13": "Green Wool",
|
||||
"35:14": "Red Wool",
|
||||
"35:15": "Black Wool",
|
||||
"37": "Dandelion",
|
||||
"38": "Rose",
|
||||
"39": "Brown Mushroom",
|
||||
"40": "Red Mushroom",
|
||||
"41": "Gold Block",
|
||||
"42": "Iron Block",
|
||||
"43": "Double Stone Slab",
|
||||
"43:1": "Double Sandstone Slab",
|
||||
"43:2": "Double Wooden Slab",
|
||||
"43:3": "Double Cobblestone Slab",
|
||||
"43:4": "Double Brick Slab",
|
||||
"43:5": "Double Stone Brick Slab",
|
||||
"43:6": "Double Nether Brick Slab",
|
||||
"43:7": "Double Quartz Slab",
|
||||
"44": "Stone Slab",
|
||||
"44:1": "Sandstone Slab",
|
||||
"44:2": "Wooden Slab",
|
||||
"44:3": "Cobblestone Slab",
|
||||
"44:4": "Brick Slab",
|
||||
"44:5": "Stone Brick Slab",
|
||||
"44:6": "Nether Brick Slab",
|
||||
"44:7": "Quartz Slab",
|
||||
"45": "Brick",
|
||||
"46": "TNT",
|
||||
"47": "Bookshelf",
|
||||
"48": "Mossy Cobblestone",
|
||||
"49": "Obsidian",
|
||||
"50": "Torch",
|
||||
"51": "Fire",
|
||||
"52": "Monster Spawner",
|
||||
"53": "Oak Wood Stairs",
|
||||
"54": "Chest",
|
||||
"55": "Redstone Wire",
|
||||
"56": "Diamond Ore",
|
||||
"57": "Diamond Block",
|
||||
"58": "Workbench",
|
||||
"59": "Wheat Crops",
|
||||
"60": "Soil",
|
||||
"61": "Furnace",
|
||||
"62": "Burning Furnace",
|
||||
"63": "Sign Post",
|
||||
"64": "Wooden Door Block",
|
||||
"65": "Ladder",
|
||||
"66": "Rails",
|
||||
"67": "Cobblestone Stairs",
|
||||
"68": "Wall Sign",
|
||||
"69": "Lever",
|
||||
"70": "Stone Pressure Plate",
|
||||
"71": "Iron Door Block",
|
||||
"72": "Wooden Pressure Plate",
|
||||
"73": "Redstone Ore",
|
||||
"74": "Glowing Redstone Ore",
|
||||
"75": "Redstone Torch(off)",
|
||||
"76": "Redstone Torch(on)",
|
||||
"77": "Stone Button",
|
||||
"78": "Snow",
|
||||
"79": "Ice",
|
||||
"80": "Snow Block",
|
||||
"81": "Cactus",
|
||||
"82": "Clay",
|
||||
"83": "Sugar Cane",
|
||||
"84": "Jukebox",
|
||||
"85": "Fence",
|
||||
"86": "Pumpkin",
|
||||
"87": "Netherrack",
|
||||
"88": "Soul Sand",
|
||||
"89": "Glowstone",
|
||||
"90": "Portal",
|
||||
"91": "Jack - O - Lantern",
|
||||
"92": "Cake Block",
|
||||
"93": "Redstone Repeater Block(off)",
|
||||
"94": "Redstone Repeater Block(on)",
|
||||
"95": "Locked Chest",
|
||||
"96": "Trapdoor",
|
||||
"97": "Stone(Silverfish)",
|
||||
"97:1": "Cobblestone(Silverfish)",
|
||||
"97:2": "Stone Brick(Silverfish)",
|
||||
"98": "Stone Brick",
|
||||
"98:1": "Mossy Stone Brick",
|
||||
"98:2": "Cracked Stone Brick",
|
||||
"98:3": "Chiseled Stone Brick",
|
||||
"99": "Red Mushroom Cap",
|
||||
"100": "Brown Mushroom Cap",
|
||||
"101": "Iron Bars",
|
||||
"102": "Glass Pane",
|
||||
"103": "Melon Block",
|
||||
"104": "Pumpkin Stem",
|
||||
"105": "Melon Stem",
|
||||
"106": "Vines",
|
||||
"107": "Fence Gate",
|
||||
"108": "Brick Stairs",
|
||||
"109": "Stone Brick Stairs",
|
||||
"110": "Mycelium",
|
||||
"111": "Lily Pad",
|
||||
"112": "Nether Brick",
|
||||
"113": "Nether Brick Fence",
|
||||
"114": "Nether Brick Stairs",
|
||||
"115": "Nether Wart",
|
||||
"116": "Enchantment Table",
|
||||
"117": "Brewing Stand",
|
||||
"118": "Cauldron",
|
||||
"119": "End Portal",
|
||||
"120": "End Portal Frame",
|
||||
"121": "End Stone",
|
||||
"122": "Dragon Egg",
|
||||
"123": "Redstone Lamp(inactive)",
|
||||
"124": "Redstone Lamp(active)",
|
||||
"125": "Double Oak Wood Slab",
|
||||
"125:1": "Double Spruce Wood Slab",
|
||||
"125:2": "Double Birch Wood Slab",
|
||||
"125:3": "Double Jungle Wood Slab",
|
||||
"126": "Oak Wood Slab",
|
||||
"126:1": "Spruce Wood Slab",
|
||||
"126:2": "Birch Wood Slab",
|
||||
"126:3": "Jungle Wood Slab",
|
||||
"127": "Cocoa Plant",
|
||||
"128": "Sandstone Stairs",
|
||||
"129": "Emerald Ore",
|
||||
"130": "Ender Chest",
|
||||
"131": "Tripwire Hook",
|
||||
"132": "Tripwire",
|
||||
"133": "Emerald Block",
|
||||
"134": "Spruce Wood Stairs",
|
||||
"135": "Birch Wood Stairs",
|
||||
"136": "Jungle Wood Stairs",
|
||||
"137": "Command Block",
|
||||
"138": "Beacon Block",
|
||||
"139": "Cobblestone Wall",
|
||||
"139:1": "Mossy Cobblestone Wall",
|
||||
"140": "Flower Pot",
|
||||
"141": "Carrots",
|
||||
"142": "Potatoes",
|
||||
"143": "Wooden Button",
|
||||
"144": "Mob Head",
|
||||
"145": "Anvil",
|
||||
"146": "Trapped Chest",
|
||||
"147": "Weighted Pressure Plate(light)",
|
||||
"148": "Weighted Pressure Plate(heavy)",
|
||||
"149": "Redstone Comparator(inactive)",
|
||||
"150": "Redstone Comparator(active)",
|
||||
"151": "Daylight Sensor",
|
||||
"152": "Redstone Block",
|
||||
"153": "Nether Quartz Ore",
|
||||
"154": "Hopper",
|
||||
"155": "Quartz Block",
|
||||
"155:1": "Chiseled Quartz Block",
|
||||
"155:2": "Pillar Quartz Block",
|
||||
"156": "Quartz Stairs",
|
||||
"157": "Activator Rail",
|
||||
"158": "Dropper",
|
||||
"159": "White Stained Clay",
|
||||
"159:1": "Orange Stained Clay",
|
||||
"159:2": "Magenta Stained Clay",
|
||||
"159:3": "Light Blue Stained Clay",
|
||||
"159:4": "Yellow Stained Clay",
|
||||
"159:5": "Lime Stained Clay",
|
||||
"159:6": "Pink Stained Clay",
|
||||
"159:7": "Gray Stained Clay",
|
||||
"159:8": "Light Gray Stained Clay",
|
||||
"159:9": "Cyan Stained Clay",
|
||||
"159:10": "Purple Stained Clay",
|
||||
"159:11": "Blue Stained Clay",
|
||||
"159:12": "Brown Stained Clay",
|
||||
"159:13": "Green Stained Clay",
|
||||
"159:14": "Red Stained Clay",
|
||||
"159:15": "Black Stained Clay",
|
||||
"170": "Hay Bale",
|
||||
"171": "White Carpet",
|
||||
"171:1": "Orange Carpet",
|
||||
"171:2": "Magenta Carpet",
|
||||
"171:3": "Light Blue Carpet",
|
||||
"171:4": "Yellow Carpet",
|
||||
"171:5": "Lime Carpet",
|
||||
"171:6": "Pink Carpet",
|
||||
"171:7": "Gray Carpet",
|
||||
"171:8": "Light Gray Carpet",
|
||||
"171:9": "Cyan Carpet",
|
||||
"171:10": "Purple Carpet",
|
||||
"171:11": "Blue Carpet",
|
||||
"171:12": "Brown Carpet",
|
||||
"171:13": "Green Carpet",
|
||||
"171:14": "Red Carpet",
|
||||
"171:15": "Black Carpet",
|
||||
"172": "Hardened Clay",
|
||||
"173": "Block of Coal",
|
||||
"256": "Iron Shovel",
|
||||
"257": "Iron Pickaxe",
|
||||
"258": "Iron Axe",
|
||||
"259": "Flint and Steel",
|
||||
"260": "Apple",
|
||||
"261": "Bow",
|
||||
"262": "Arrow",
|
||||
"263": "Coal",
|
||||
"263:1": "Charcoal",
|
||||
"264": "Diamond",
|
||||
"265": "Iron Ingot",
|
||||
"266": "Gold Ingot",
|
||||
"267": "Iron Sword",
|
||||
"268": "Wooden Sword",
|
||||
"269": "Wooden Shovel",
|
||||
"270": "Wooden Pickaxe",
|
||||
"271": "Wooden Axe",
|
||||
"272": "Stone Sword",
|
||||
"273": "Stone Shovel",
|
||||
"274": "Stone Pickaxe",
|
||||
"275": "Stone Axe",
|
||||
"276": "Diamond Sword",
|
||||
"277": "Diamond Shovel",
|
||||
"278": "Diamond Pickaxe",
|
||||
"279": "Diamond Axe",
|
||||
"280": "Stick",
|
||||
"281": "Bowl",
|
||||
"282": "Mushroom Soup",
|
||||
"283": "Gold Sword",
|
||||
"284": "Gold Shovel",
|
||||
"285": "Gold Pickaxe",
|
||||
"286": "Gold Axe",
|
||||
"287": "String",
|
||||
"288": "Feather",
|
||||
"289": "Sulphur",
|
||||
"290": "Wooden Hoe",
|
||||
"291": "Stone Hoe",
|
||||
"292": "Iron Hoe",
|
||||
"293": "Diamond Hoe",
|
||||
"294": "Gold Hoe",
|
||||
"295": "Wheat Seeds",
|
||||
"296": "Wheat",
|
||||
"297": "Bread",
|
||||
"298": "Leather Helmet",
|
||||
"299": "Leather Chestplate",
|
||||
"300": "Leather Leggings",
|
||||
"301": "Leather Boots",
|
||||
"302": "Chainmail Helmet",
|
||||
"303": "Chainmail Chestplate",
|
||||
"304": "Chainmail Leggings",
|
||||
"305": "Chainmail Boots",
|
||||
"306": "Iron Helmet",
|
||||
"307": "Iron Chestplate",
|
||||
"308": "Iron Leggings",
|
||||
"309": "Iron Boots",
|
||||
"310": "Diamond Helmet",
|
||||
"311": "Diamond Chestplate",
|
||||
"312": "Diamond Leggings",
|
||||
"313": "Diamond Boots",
|
||||
"314": "Gold Helmet",
|
||||
"315": "Gold Chestplate",
|
||||
"316": "Gold Leggings",
|
||||
"317": "Gold Boots",
|
||||
"318": "Flint",
|
||||
"319": "Raw Porkchop",
|
||||
"320": "Cooked Porkchop",
|
||||
"321": "Painting",
|
||||
"322": "Golden Apple",
|
||||
"322:1": "Enchanted Golden Apple",
|
||||
"323": "Sign",
|
||||
"324": "Wooden Door",
|
||||
"325": "Bucket",
|
||||
"326": "Water Bucket",
|
||||
"327": "Lava Bucket",
|
||||
"328": "Minecart",
|
||||
"329": "Saddle",
|
||||
"330": "Iron Door",
|
||||
"331": "Redstone",
|
||||
"332": "Snowball",
|
||||
"333": "Boat",
|
||||
"334": "Leather",
|
||||
"335": "Milk Bucket",
|
||||
"336": "Clay Brick",
|
||||
"337": "Clay Balls",
|
||||
"338": "Sugarcane",
|
||||
"339": "Paper",
|
||||
"340": "Book",
|
||||
"341": "Slimeball",
|
||||
"342": "Storage Minecart",
|
||||
"343": "Powered Minecart",
|
||||
"344": "Egg",
|
||||
"345": "Compass",
|
||||
"346": "Fishing Rod",
|
||||
"347": "Clock",
|
||||
"348": "Glowstone Dust",
|
||||
"349": "Raw Fish",
|
||||
"350": "Cooked Fish",
|
||||
"351": "Ink Sack",
|
||||
"351:1": "Rose Red",
|
||||
"351:2": "Cactus Green",
|
||||
"351:3": "Coco Beans",
|
||||
"351:4": "Lapis Lazuli",
|
||||
"351:5": "Purple Dye",
|
||||
"351:6": "Cyan Dye",
|
||||
"351:7": "Light Gray Dye",
|
||||
"351:8": "Gray Dye",
|
||||
"351:9": "Pink Dye",
|
||||
"351:10": "Lime Dye",
|
||||
"351:11": "Dandelion Yellow",
|
||||
"351:12": "Light Blue Dye",
|
||||
"351:13": "Magenta Dye",
|
||||
"351:14": "Orange Dye",
|
||||
"351:15": "Bone Meal",
|
||||
"352": "Bone",
|
||||
"353": "Sugar",
|
||||
"354": "Cake",
|
||||
"355": "Bed",
|
||||
"356": "Redstone Repeater",
|
||||
"357": "Cookie",
|
||||
"358": "Map",
|
||||
"359": "Shears",
|
||||
"360": "Melon",
|
||||
"361": "Pumpkin Seeds",
|
||||
"362": "Melon Seeds",
|
||||
"363": "Raw Beef",
|
||||
"364": "Steak",
|
||||
"365": "Raw Chicken",
|
||||
"366": "Cooked Chicken",
|
||||
"367": "Rotten Flesh",
|
||||
"368": "Ender Pearl",
|
||||
"369": "Blaze Rod",
|
||||
"370": "Ghast Tear",
|
||||
"371": "Gold Nugget",
|
||||
"372": "Nether Wart Seeds",
|
||||
"373": "Potion",
|
||||
"374": "Glass Bottle",
|
||||
"375": "Spider Eye",
|
||||
"376": "Fermented Spider Eye",
|
||||
"377": "Blaze Powder",
|
||||
"378": "Magma Cream",
|
||||
"379": "Brewing Stand",
|
||||
"380": "Cauldron",
|
||||
"381": "Eye of Ender",
|
||||
"382": "Glistering Melon",
|
||||
"383:50": "Spawn Creeper",
|
||||
"383:51": "Spawn Skeleton",
|
||||
"383:52": "Spawn Spider",
|
||||
"383:54": "Spawn Zombie",
|
||||
"383:55": "Spawn Slime",
|
||||
"383:56": "Spawn Ghast",
|
||||
"383:57": "Spawn Pigman",
|
||||
"383:58": "Spawn Enderman",
|
||||
"383:59": "Spawn Cave Spider",
|
||||
"383:60": "Spawn Silverfish ",
|
||||
"383:61": "Spawn Blaze",
|
||||
"383:62": "Spawn Magma Cube ",
|
||||
"383:65": "Spawn Bat",
|
||||
"383:66": "Spawn Witch",
|
||||
"383:90": "Spawn Pig",
|
||||
"383:91": "Spawn Sheep",
|
||||
"383:92": "Spawn Cow",
|
||||
"383:93": "Spawn Chicken",
|
||||
"383:94": "Spawn Squid",
|
||||
"383:95": "Spawn Wolf",
|
||||
"383:96": "Spawn Mooshroom",
|
||||
"383:98": "Spawn Ocelot",
|
||||
"383:100": "Spawn Horse",
|
||||
"383:120": "Spawn Villager",
|
||||
"384": "Bottle o' Enchanting",
|
||||
"385": "Fire Charge",
|
||||
"386": "Book and Quill",
|
||||
"387": "Written Book",
|
||||
"388": "Emerald",
|
||||
"389": "Item Frame",
|
||||
"390": "Flower Pot",
|
||||
"391": "Carrots",
|
||||
"392": "Potato",
|
||||
"393": "Baked Potato",
|
||||
"394": "Poisonous Potato",
|
||||
"395": "Map",
|
||||
"396": "Golden Carrot",
|
||||
"397": "Mob Head (Skeleton)",
|
||||
"397:1": "Mob Head (Wither Skeleton)",
|
||||
"397:2": "Mob Head (Zombie)",
|
||||
"397:3": "Mob Head (Human)",
|
||||
"397:4": "Mob Head (Creeper)",
|
||||
"398": "Carrot on a Stick",
|
||||
"399": "Nether Star",
|
||||
"400": "Pumpkin Pie",
|
||||
"401": "Firework Rocket",
|
||||
"402": "Firework Star",
|
||||
"403": "Enchanted Book",
|
||||
"404": "Redstone Comparator",
|
||||
"405": "Nether Brick",
|
||||
"406": "Nether Quartz",
|
||||
"407": "Minecart with TNT",
|
||||
"408": "Minecart with Hopper",
|
||||
"417": "Iron Horse Armor",
|
||||
"418": "Gold Horse Armor",
|
||||
"419": "Diamond Horse Armor",
|
||||
"420": "Lead",
|
||||
"421": "Name Tag"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user