Skip to content

Instantly share code, notes, and snippets.

@tycho
Created November 4, 2020 08:10
Show Gist options
  • Save tycho/755ad1d97b5987f31a32293fd4f67e0c to your computer and use it in GitHub Desktop.
Save tycho/755ad1d97b5987f31a32293fd4f67e0c to your computer and use it in GitHub Desktop.
simple implementation of hddtemp using smartctl and Python
#!/usr/bin/python3
#
# hddtemp server implemented with smartctl and Python
#
# Copyright (c) 2020 Steven Noonan
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
###
#
# I was annoyed that hddtemp failed to read temperatures from drives on my
# external SATA dock, but smartctl had no problem doing it. Presumably this is
# because smartctl has "-d sat" and hddtemp only understands SATA, SCSI, and
# PATA.
#
# Since we can read the same data from smartctl, we can implement the hddtemp
# protocol and just use smartctl for the heavy lifting.
#
###
#
# hddtemp's actual protocol is also really simple. It accepts a connection,
# sends a bunch of pipe-delimited data, and then closes the connection. For
# example:
#
# |/dev/sda|WDC WUH721414ALE6L4|40|C||/dev/sdb|WDC WUH721414ALE6L4|39|C|
#
import glob
import json
import socketserver
import subprocess
import sys
def hddtemp():
devs = []
for dev in sorted(glob.glob('/dev/sd[a-z]')):
try:
stdout = subprocess.check_output(['smartctl', '-A', '-i', '-j', dev])
meta = json.loads(stdout.decode('utf-8'))
devs.append('|%s|%s|%s|C|' % (dev, ' '.join(meta['model_name'].split()), meta['temperature']['current']))
except:
pass
return ''.join(devs)
class HDDTempHandler(socketserver.BaseRequestHandler):
def handle(self):
self.request.sendall(hddtemp().encode('utf-8'))
def main():
server_address = ('localhost', 7634)
server = socketserver.ForkingTCPServer(server_address, HDDTempHandler)
server.serve_forever()
server.server_close()
if __name__ == "__main__":
socketserver.ForkingTCPServer.allow_reuse_address = True
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment