Run script python with HA

Hi all,
I’m trying to run a python script in HA, I created the folder in my repository and insert the code in cofiguration.yaml (python_script:).
If I run the script with “thonny, Python IDE” it run with no problems.

In HA I found the service “python_script.campanello2” but if I click “call service” nothing happens…

This is the LOG:

Error executing script: __import__ not found
Traceback (most recent call last):
  File "/srv/homeassistant/lib/python3.8/site-packages/homeassistant/components/python_script/__init__.py", line 217, in execute
    exec(compiled.code, restricted_globals)
  File "campanello2.py", line 1, in <module>
ImportError: __import__ not found

Please share your code that you are trying to run, how you are trying to trigger it, and then execute it. I’m assuming it’s in an automation (?)

Additionally, you need to have the following in your configuration.yaml file:

python_script:

This let’s you use the service.

You can then call the python script by adding something like the following to your action section:

  - service: python_script.py_script_history_attributes
    data_template:
      entity_id: sensor.cleaning_ladies_time_at_house
      allow_create: True

In this case, I have a file called py_script_history_attributes.py in the folder: \\hassio\config\python_scripts

Here are the docs: Python Scripts - Home Assistant (home-assistant.io)

Basically it’s a script that take a picture from the ip camera and sends it to email:

import requests
import shutil
import os
import smtplib
import RPi.GPIO as GPIO
import time
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
# This is the image url.
image_url = 'http://192.168.0.19/tmpfs/auto.jpg/'
username = ''
password = '!!'
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = '[email protected]' #change this to match your gmail account
GMAIL_PASSWORD = 'c'  #change this to match your gmail password
#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)
#Set digital pin 17(BCM) to an input
GPIO.setup(17, GPIO.IN)
#Set digital pin 17(BCM) to an input and enable the pullup
GPIO.setup(17, GPIO.IN)#, pull_up_down=GPIO.PUD_UP)
#Event to detect button press
GPIO.add_event_detect(17, GPIO.FALLING)
class Emailer:
    def sendmail(self, recipient, subject, content, image):
        #Create Headers
        emailData = MIMEMultipart()
        emailData['Subject'] = subject
        emailData['To'] = recipient
        emailData['From'] = GMAIL_USERNAME
        #Attach our text data
        emailData.attach(MIMEText(content))
         #Create our Image Data from the defined image
        imageData = MIMEImage(open(image, 'rb').read(), 'jpg')
        imageData.add_header('Content-Disposition', 'attachment; filename="image.jpg"')
        emailData.attach(imageData)
        #Connect to Gmail Server
        session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
        session.ehlo()
        session.starttls()
        session.ehlo()
        #Login to Gmail
        session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
        #Send Email & Exit
        session.sendmail(GMAIL_USERNAME, recipient, emailData.as_string())
        session.quit
sender = Emailer()


time.sleep(1.5)
            # Open the url image, set stream to True, this will return the stream content.
resp = requests.get(image_url, auth=(username, password), stream=True)
            # Open a local file with wb ( write binary ) permission.
local_file = open('/home/pi/Desktop/LOGcampanello/cam.jpg', 'wb')
            # Set decode_content value to True, otherwise the downloaded image file's size will be zero.
resp.raw.decode_content = True
            # Copy the response stream raw data to local image file.
shutil.copyfileobj(resp.raw, local_file)
            # Remove the image url response object.
del resp
            #creo il file con l'orario come nome
new_filename='/home/pi/Desktop/LOGcampanello/'+ time.strftime("%d%m%Y-%H:%M:%S.jpg")
            #rinomino il file scaricato dalla telecamera
os.rename("/home/pi/Desktop/LOGcampanello/cam.jpg", new_filename)
            #invio mail
emailSubject = "Campanello"
emailContent = "Hanno suonato alle: " + time.ctime()
 
sender.sendmail('[email protected]', emailSubject, emailContent, new_filename)
print("Email1 Sent")
sender.sendmail('[email protected]', emailSubject, emailContent, new_filename)
print("Email2 Sent")
time.sleep(6)

From https://www.home-assistant.io/integrations/python_script/

It is not possible to use Python imports with this integration. If you want to do more advanced scripts, you can take a look at AppDaemon or pyscript

Yep - @ludeeus is spot on. While Python scripts are very powerful to use, they are limited - i.e., no imports. You have what you have. For those situations I use AppDaemon.

Hello there,
you can’t use import inside python_script integration.

It is not possible to use Python imports with this integration. If you want to do more advanced scripts, you can take a look at AppDaemon or pyscript

What I use for running python scripts with import is a command_line sensor (https://www.home-assistant.io/integrations/sensor.command_line/). Or you can use AppDaemon or pyscript like doc says but I haven’t used it so far.

Thanks to all, I installed pyscript by HACS…
In HA logs I see this error:
Exception in </home/homeassistant/.homeassistant/pyscript/campanello2.py> line 50: local_file = open("/home/pi/Desktop/LOGcampanello/cam.jpg", 'wb') ^ NameError: name 'open' is not defined

But if I run the script with Thonny python IDE I don’ have errors…

pyscript, out of the box, does not allow any blocking calls (like open) as they would block all of Home Assistant. Reading a file in has to be done in a slightly different way.

Here’s a quick chunk of untested code that should get you started (only works with “master” version of pyscript since pyscript_compile is fairly new):

@pyscript_compile
def blocking_read_file(filename):
    f = open(filename, "r")
    data = f.read()
    f.close()
    return data

def read_file(filename):
    x = task.executor(blocking_read_file, filename)
    return x


def somefunction():
  file_contents = read_file("/home/pi/Desktop/LOGcampanello/cam.jpg")
1 Like

thanks for your help… Honestly I think to discard the idea to runs the script by an automation of HA. Now the script runs as service and it executes when a GPIO event occours…
But honestly I have trouble programming in Python…

I created the code joining various script found on the net, and it works (but i don’t understand it completely)

resp = requests.get(image_url, auth=(username, password), stream=True)
# Open a local file with wb ( write binary ) permission.
local_file = open('/home/pi/Desktop/LOGcampanello/cam.jpg', 'wb')
# Set decode_content value to True, otherwise the downloaded image file's size will be zero.
resp.raw.decode_content = True
# Copy the response stream raw data to local image file.
shutil.copyfileobj(resp.raw, local_file)
# Remove the image url response object.
del resp
#creo il file con l'orario come nome
new_filename='/home/pi/Desktop/LOGcampanello/'+ time.strftime("%d%m%Y-%H:%M:%S.jpg")
#rinomino il file scaricato dalla telecamera
os.rename("/home/pi/Desktop/LOGcampanello/cam.jpg", new_filename)
#invio mail
emailSubject = "Campanello"
emailContent = "Hanno suonato alle: " + time.ctime()
 
sender.sendmail('[email protected]', emailSubject, emailContent, new_filename)
print("Email1 Sent")

Maybe the code could easily “repaired” but I don’t able to do this…

How do you use the command line sensor with python scripts ? My script does not even want to start and its simple one defined like this:

 platform: command_line
  unique_id: garmin_venu2sq_amzn
  name: Garmin Venu 2 Sq Amazon
  command: "python3 scripts/garmin_venu_amazon.py"
  scan_interval: 21600
  value_template: '{{ value.Split("$")[1] | float }}'