Raspberry Pi Monitor

Hi,

I replied to your bug you opened in GitHub. For UPnP the host IP address must be specified in the configuration files first. I’ve tried to detail it in a reply on GitHub. Let me know if that worked.

First as in BEFORE you compile ?

Yes, modifiy properties file, save, mvn clean install and than start the jar up again

Ya its not that clear then… you have BUILD first in the README.md

And you got a lot of misspellings too.

The README.md is not in order but you’re right I could do a better job documenting this. I’ll update the README.md when I’ll have some time!

For those of you that are using the JANI monitoring without the UPnP I have a modified version of the pom.xml file that will detect the new PI 3B+

Let me know if you want it.

2 Likes

@cl0udninja KUDOS for your hard work !!

If you don’t mind I would like to port this over for HE… is that ok ?

I don’t, but what is HE? :slight_smile:

Hubitat Elevation – another smart hub

For those who use AT and want to monitor your PI temperatures using the Raspberry Pi Monitor (Manual IP) groovy below is the modified version to do that.

/**
 *  Raspberry Pi Monitor
 *
 *  Monitor your Raspberry Pi using SmartThings and Raspberry Pi Monitor <https://github.com/cl0udninja/raspberrypi.monitor>
 *
 *  Licensed under the GNU v3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
 *
 *  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.
 *
 */
preferences {		
	input("ip", "string", title:"IP Address", description: "192.168.1.150", defaultValue: "192.168.1.150" ,required: true, displayDuringSetup: true)		
	input("port", "string", title:"Port", description: "80", defaultValue: "80" , required: true, displayDuringSetup: true)		
}
metadata {
	definition (name: "Raspberry Pi Monitor (Manual IP)", namespace: "cl0udninja", author: "Janos Elohazi") {
		capability "Polling"
		capability "Refresh"
		capability "Temperature Measurement"
        capability "Sensor"
        capability "Health Check"
        
        attribute "cpuFrequency", "number"       
        attribute "freeMemory", "number"
        attribute "cpuCoreVoltage", "number"
        attribute "modelName", "string"
        attribute "boardType", "string"
        attribute "javaVersion", "string"
        attribute "hostname", "string"
        attribute "serialNumber", "string"
	}

	simulator {
		// TODO: define status and reply messages here
	}

	tiles(scale: 2) {
		valueTile("Temperature", "device.cpuTemperature", width: 6, height: 4, canChangeIcon: true) {
            state "cpuTemperature", label:'${currentValue}°',
			icon: "http://storage.googleapis.com/storage.cl0ud.ninja/raspberry-pi-logo.png"
			backgroundColors:[
            	[value: 25, color: "#153591"],
                [value: 35, color: "#1e9cbb"],
                [value: 47, color: "#90d2a7"],
                [value: 59, color: "#44b621"],
                [value: 67, color: "#f1d801"],
                [value: 76, color: "#d04e00"],
                [value: 77, color: "#bc2323"]
            ]
        }
        valueTile("freeMemoryLabel", "device.label.freeMemory", width: 3, height: 1) {
        	state "default", label:'Free memory'
        }
        valueTile("freeMemory", "device.freeMemory", width: 2, height: 1) {
        	state "default", label:'${currentValue}\nMB'
        }
        valueTile("freeMemoryPercent", "device.freeMemoryPercent", width: 1, height: 1) {
            state "freeMemoryPercent", label:'${currentValue}%',
            backgroundColors:[
                [value: 0, color: "#44b621"],
                [value: 50, color: "#44b621"],
                [value: 70, color: "#f1d801"],
                [value: 80, color: "#d04e00"],
                [value: 90, color: "#bc2323"]
            ]
        }
        valueTile("cpuCoreVoltage", "device.cpuCoreVoltage", width: 2, height: 2) {
        	state "default", label:'CPU:\n${currentValue} V',
            backgroundColors:[
                [value: 1.1, color: "#bc2323"],
                [value: 1.2, color: "#44b621"],
                [value: 1.3, color: "#bc2323"]
            ]
        }
		valueTile("modelName", "device.modelName", width: 2, height:1) {
        	state "default", label:'Model name:\n${currentValue}'
        }
        valueTile("boardType", "device.boardType", width: 2, height:1) {
        	state "default", label:'Board type:\n${currentValue}'
        }
        valueTile("javaVersion", "device.javaVersion", width: 2, height:1) {
        	state "default", label:'Java version:\n${currentValue}'
        }
        valueTile("hostname", "device.hostname", width: 2, height:1) {
        	state "default", label:'Hostname:\n${currentValue}'
        }
        standardTile("refresh", "device.refresh", inactiveLabel: false, width: 1, height: 1, decoration: "flat") {
        	state "default", action:"refresh.refresh", icon: "st.secondary.refresh"
        }
        
        main "Temperature"
        
        details(["Temperature", "freeMemoryLabel", "freeMemory", "freeMemoryPercent", "cpuCoreVoltage", "modelName", "boardType", "javaVersion", "hostname", "refresh"])
    }
}

def installed() {
	log.debug "installed"
	initialize();
}

def updated() {
	log.debug "updated"
	initialize();
}

def ping() {
	log.debug "ping"
	poll()
}

def initialize() {
	log.debug "initialize"
	sendEvent(name: "checkInterval", value: 60 * 10, data: [protocol: "cloud"], displayed: false)
    refresh()
}
// parse events into attributes
def parse(description) {
    log.debug "Parsing '${description?.json}'"
	def msg = parseLanMessage(description?.body)
    log.debug "Msg ${msg}"
	def json = parseJson(description?.body)
    log.debug "JSON '${json}'"
    
    if (json.containsKey("cpuTemperature")) {
    	if (getTemperatureScale() == "C") {
	    	sendEvent(name: "temperature", value: json.cpuTemperature)
        } else {
        	def fahrenheit = json.cpuTemperature * 9 / 5 + 32
            sendEvent(name: "temperature", value: fahrenheit)
        }
    }
    if (json.containsKey("freeMemory")) {
    	sendEvent(name: "freeMemory", value: (json.freeMemory/1024/1024).toDouble().round(2))
        if (json.containsKey("totalMemory")) {
        	
        	sendEvent(name: "freeMemoryPercent", value: (json.freeMemory/json.totalMemory*100).toDouble().round())
        }
    }
    if (json.containsKey("cpuCoreVoltage")) {
    	sendEvent(name: "cpuCoreVoltage", value: json.cpuCoreVoltage)
    }
    if (json.containsKey("modelName")) {
    	sendEvent(name: "modelName", value: json.modelName)
    }
    if (json.containsKey("boardType")) {
    	sendEvent(name: "boardType", value: json.boardType)
    }
    if (json.containsKey("javaVersion")) {
    	sendEvent(name: "javaVersion", value: json.javaVersion)
    }
    if (json.containsKey("hostname")) {
    	sendEvent(name: "hostname", value: json.hostname)
    }
    if (json.containsKey("serialNumber")) {
    	sendEvent(name: "serialNumber", value: json.serialNumber)
    }
}

// handle commands
def poll() {
	log.debug "Executing 'poll'"
    getPiInfo()
}

def refresh() {
	log.debug "Executing 'refresh'"
    getPiInfo()
}

private getPiInfo() {
	def iphex = convertIPtoHex(ip)
    def porthex = convertPortToHex(port)
    
	def uri = "/api/pi"
    def headers=[:]
    headers.put("HOST", "${ip}:${port}")
    headers.put("Accept", "application/json")
    def hubAction = new physicalgraph.device.HubAction(
        method: "GET",
        path: uri,
		headers: headers,
        "${iphex}:${porthex}",
        [callback: parse]
    )
    log.debug "Getting Pi data ${hubAction}"
    hubAction 
}

private String convertIPtoHex(ipAddress) {
	log.debug "convertIPtoHex ${ipAddress} to hex"
    String hex = ipAddress.tokenize( '.' ).collect {  String.format( '%02x', it.toInteger() ) }.join()
    return hex
}

private String convertPortToHex(port) {
	log.debug "convertPortToHex ${port} to hex"
	String hexport = port.toString().format( '%04x', port.toInteger() )
    return hexport
}

private Integer convertHexToInt(hex) {
    return Integer.parseInt(hex,16)
}

private String convertHexToIP(hex) {
    return [convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
}
def sync(ip, port) {
	log.debug "sync ${ip} ${port}"
	def existingIp = getDataValue("ip")
	def existingPort = getDataValue("port")
	if (ip && ip != existingIp) {
		updateDataValue("ip", ip)
	}
	if (port && port != existingPort) {
		updateDataValue("port", port)
	}
    def ipHex = convertIPToHex(ip)
    def portHex = convertPortToHex(port)
    device.deviceNetworkId = "${ipHex}:${portHex}"
}
1 Like

Making progress but sadly still not working yet. Says build success at the end but noticed that my .jar file doesn’t have the same name as the one mentioned in the GitHub installation info as mines named “raspberrypi.monitor-0.0.1-SNAPSHOT.jar” and not sure what the snapshot is all about. Worse yet I’m getting an error page saying “This site can’t be reached” when entering the URL “http://raspberrypi:8080/api/pi” but in my case it’s “http://pecan:8080/api/pi”.

Any ideas?

if the name is different that’s not a big deal. You’ll have to run it with sudo though. I.e.: sudo java -jar /home/pi/raspberrypi.monitor-master/target/raspberrypi.monitor-0.0.1.SNAPSHOT.jar Then it would spit out on the console if it has any problems (it shouldn’t). If you want to run it as a service you’ll have to add the above line to your rc.local and reboot the pi. After that the URL should be available. Let me know if you need more help!

Thanks for getting back to me - didn’t know that last step about running it with sudo-. I looked into putting that line of code into the rc.local file, but wasn’t sure if I should go after everything else that’s already in there or if I should go before the last line with the word exit.

do it above the line with exit 0. exit 0 will quit the script and anything after it will never be executed.

Will you ever add any control of GPIO pins or no? If not do you know of any SmartThings handlers/smartapps that control GPIO?

This is just a monitor app. I have other apps that do control GPIO ports. Check out my repositories. Those are although public I didn’t document them at all… But if you look at the code you can see what they’re doing.

This one?

With these installed?

Another question for you - any idea why the temperature always shows up as 0° in webCoRE?

I think because it’s called cpuTemperature not temperature