Update
This commit is contained in:
parent
6ecbf02c5e
commit
ff87b1877a
205
fup-anemometer-user.py
Executable file
205
fup-anemometer-user.py
Executable file
@ -0,0 +1,205 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
OSC/Random Example: send random numbers to OSC.
|
||||||
|
|
||||||
|
This example sends a pseudo-random number between 0 and 1024
|
||||||
|
to the OSC receiver on UDP port 2222.
|
||||||
|
"""
|
||||||
|
from pythonosc import udp_client
|
||||||
|
from pythonosc import osc_message_builder
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
# import urllib library
|
||||||
|
import urllib.request
|
||||||
|
import urllib.error
|
||||||
|
|
||||||
|
# import json
|
||||||
|
import json
|
||||||
|
|
||||||
|
# import argparse
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
# Logging to file
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# Errors codes
|
||||||
|
OSC_no_error = 0
|
||||||
|
OSC_error = 1
|
||||||
|
OSC_meteobridge_url_error = 11
|
||||||
|
OSC_meteobridge_http_error = 12
|
||||||
|
OSC_meteobridge_nosensor_error = 20
|
||||||
|
OSC_meteobridge_restart = 30
|
||||||
|
|
||||||
|
# Debug flags
|
||||||
|
debug_args_print = True
|
||||||
|
debug_json_print = True
|
||||||
|
debug_urllib_print = True
|
||||||
|
debug_restart_print = True
|
||||||
|
debug_osc = False
|
||||||
|
debug_working_directory = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
# OSC Addresses
|
||||||
|
osc_error_addr = "/env_sensors/anemometer/error"
|
||||||
|
osc_speed_addr = "/env_sensors/anemometer/speed"
|
||||||
|
osc_battery_addr = "/env_sensors/anemometer/battery"
|
||||||
|
osc_age_addr = "/env_sensors/anemometer/age"
|
||||||
|
osc_signal_addr = "/env_sensors/anemometer/signal"
|
||||||
|
|
||||||
|
|
||||||
|
# define urllib timeout in seconds
|
||||||
|
url_timeout = 120
|
||||||
|
|
||||||
|
# max error number before self restart
|
||||||
|
# max_error_rst = 3
|
||||||
|
|
||||||
|
prod_flag = False
|
||||||
|
prod_working_directory = "/usr/local/com.fup.anemometre_daemon"
|
||||||
|
|
||||||
|
meteobridge_template = "cgi-bin/template.cgi?template={%22time%22:%22[DD][MM][YYYY][hh][mm][ss]%22,%22speed%22:[wind0wind-act],%22lastspeed%22:[wind0wind-lastval],%22battery%22:[wind0lowbat-act.0],%22wind-age%22:[wind0wind-age],%22signal%22:[wind0signal-act.0]}"
|
||||||
|
|
||||||
|
def send_osc_message(osc_sender, osc_address, osc_arg):
|
||||||
|
msg = osc_message_builder.OscMessageBuilder(address = osc_address)
|
||||||
|
msg.add_arg(osc_arg)
|
||||||
|
osc_sender.send(msg.build())
|
||||||
|
|
||||||
|
def main(meteobridge_url, meteobridge_user, meteobridge_passwd, max_host, max_port, errors_restart):
|
||||||
|
|
||||||
|
error_counter = 0
|
||||||
|
|
||||||
|
oscSender = udp_client.UDPClient(max_host, max_port)
|
||||||
|
|
||||||
|
meteobridge_sensor_req = meteobridge_url + meteobridge_template
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
logging.basicConfig(filename='fup_anemometer.log', encoding='utf-8', format='%(asctime)s-%(levelname)s:%(message)s', datefmt='%Y/%m/%d %H:%M:%S', level=logging.DEBUG)
|
||||||
|
logging.info("fup_anemometer started")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
# http auth to meteobridge
|
||||||
|
passman = urllib.request.HTTPPasswordMgrWithDefaultRealm()
|
||||||
|
passman.add_password(None, meteobridge_url, meteobridge_user, meteobridge_passwd)
|
||||||
|
authhandler = urllib.request.HTTPBasicAuthHandler(passman)
|
||||||
|
opener = urllib.request.build_opener(authhandler)
|
||||||
|
urllib.request.install_opener(opener)
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = urllib.request.urlopen(meteobridge_sensor_req, timeout = url_timeout)
|
||||||
|
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
if debug_urllib_print:
|
||||||
|
print('HTTP Error code: ', e.code)
|
||||||
|
logging.error("Get sensor datas from : " + meteobridge_url + " - HTTP Error code: " + str(e.code))
|
||||||
|
error_counter += 1
|
||||||
|
send_osc_message(oscSender, osc_error_addr, OSC_meteobridge_http_error)
|
||||||
|
# msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
||||||
|
# msg.add_arg(OSC_meteobridge_http_error)
|
||||||
|
# oscSender.send(msg.build())
|
||||||
|
# Sleep 5 seconds if error
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
except urllib.error.URLError as e:
|
||||||
|
if debug_urllib_print:
|
||||||
|
print('URL Error Reason: ', e.reason)
|
||||||
|
logging.error("Get sensor datas from : " + meteobridge_url + " - URL Error Reason: " + str(e.reason))
|
||||||
|
error_counter += 1
|
||||||
|
send_osc_message(oscSender, osc_error_addr, OSC_meteobridge_url_error)
|
||||||
|
# msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
||||||
|
# msg.add_arg(OSC_meteobridge_url_error)
|
||||||
|
# oscSender.send(msg.build())
|
||||||
|
# Sleep 5 seconds if error
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
data_json = json.loads(response.read())
|
||||||
|
if debug_json_print == True:
|
||||||
|
print(data_json)
|
||||||
|
wind_speed = float(data_json["speed"])
|
||||||
|
wind_lastspeed = float(data_json["lastspeed"])
|
||||||
|
wind_batt = int(data_json["battery"])
|
||||||
|
wind_age = int(data_json["wind-age"])
|
||||||
|
wind_signal = int(data_json["signal"])
|
||||||
|
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
if debug_json_print:
|
||||||
|
print("Invalid JSON syntax:", e)
|
||||||
|
logging.error("Decode JSON from : " + meteobridge_url + " - Invalid JSON syntax : " + str(e))
|
||||||
|
error_counter += 1
|
||||||
|
send_osc_message(oscSender, osc_error_addr, OSC_meteobridge_nosensor_error)
|
||||||
|
# msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
||||||
|
# msg.add_arg(OSC_meteobridge_nosensor_error)
|
||||||
|
# oscSender.send(msg.build())
|
||||||
|
# Sleep 5 seconds if error
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
else:
|
||||||
|
error_counter = 0
|
||||||
|
|
||||||
|
send_osc_message(oscSender, osc_speed_addr, wind_lastspeed)
|
||||||
|
# msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/speed")
|
||||||
|
# msg.add_arg(wind_lastspeed)
|
||||||
|
# oscSender.send(msg.build())
|
||||||
|
|
||||||
|
send_osc_message(oscSender, osc_battery_addr, wind_batt)
|
||||||
|
# msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/battery")
|
||||||
|
# msg.add_arg(wind_batt)
|
||||||
|
# oscSender.send(msg.build())
|
||||||
|
|
||||||
|
send_osc_message(oscSender, osc_age_addr, wind_age)
|
||||||
|
# msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/age")
|
||||||
|
# msg.add_arg(wind_age)
|
||||||
|
# oscSender.send(msg.build())
|
||||||
|
|
||||||
|
send_osc_message(oscSender, osc_signal_addr, wind_signal)
|
||||||
|
# msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/signal")
|
||||||
|
# msg.add_arg(wind_signal)
|
||||||
|
# oscSender.send(msg.build())
|
||||||
|
|
||||||
|
send_osc_message(oscSender, osc_error_addr, OSC_no_error)
|
||||||
|
# msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
||||||
|
# msg.add_arg(OSC_no_error)
|
||||||
|
# oscSender.send(msg.build())
|
||||||
|
|
||||||
|
if debug_osc:
|
||||||
|
logging.debug("OSC datas sent")
|
||||||
|
# Sleep 2 seconds if no errors
|
||||||
|
time.sleep(2)
|
||||||
|
# Self restart
|
||||||
|
if error_counter >= errors_restart:
|
||||||
|
send_osc_message(oscSender, osc_error_addr, OSC_meteobridge_restart)
|
||||||
|
# msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
||||||
|
# msg.add_arg(OSC_meteobridge_restart)
|
||||||
|
# oscSender.send(msg.build())
|
||||||
|
time.sleep(1)
|
||||||
|
if debug_restart_print:
|
||||||
|
print("Current errors count : " + str(error_counter) + " / " + errors_restart + " max errors")
|
||||||
|
print("Too many errors restarting program ...")
|
||||||
|
logging.error("Current errors count : " + str(error_counter) + " / " + errors_restart + " max errors")
|
||||||
|
logging.error("Too many errors restarting program ...")
|
||||||
|
os.execv(sys.executable, ['python'] + sys.argv)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description="FUP anemometer for OSC")
|
||||||
|
parser.add_argument('-url', '--url-meteobridge', default='http://192.168.0.39/')
|
||||||
|
parser.add_argument('-u', '--user-meteobridge', default='meteobridge')
|
||||||
|
parser.add_argument('-p', '--passwd-meteobridge',default='meteobridge')
|
||||||
|
parser.add_argument('-mh', '--max-host', default='localhost')
|
||||||
|
parser.add_argument('-mp','--max-port', default=2222, type=int)
|
||||||
|
parser.add_argument('-e', '--errors-restart', default=20, type=int)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# if debug_args_print is True, print arguments
|
||||||
|
if debug_args_print:
|
||||||
|
print('Meteobridge URL:', args.url_meteobridge)
|
||||||
|
print('Meteobridge User:', args.user_meteobridge)
|
||||||
|
print('Meteobridge Password:', args.passwd_meteobridge)
|
||||||
|
print('OSC host:', args.max_host)
|
||||||
|
print('OSC port:', args.max_port)
|
||||||
|
print('Errors restart:', args.errors_restart)
|
||||||
|
|
||||||
|
main(meteobridge_url=args.url_meteobridge, meteobridge_user=args.user_meteobridge, meteobridge_passwd=args.passwd_meteobridge, max_host=args.max_host, max_port=args.max_port, errors_restart=args.errors_restart)
|
@ -1,222 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
OSC/Random Example: send random numbers to OSC.
|
|
||||||
|
|
||||||
This example sends a pseudo-random number between 0 and 1024
|
|
||||||
to the OSC receiver on UDP port 2222.
|
|
||||||
"""
|
|
||||||
from pythonosc import udp_client
|
|
||||||
from pythonosc import osc_message_builder
|
|
||||||
import time
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
# import urllib library
|
|
||||||
import urllib.request
|
|
||||||
import urllib.error
|
|
||||||
|
|
||||||
# import json
|
|
||||||
import json
|
|
||||||
|
|
||||||
# import argparse
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
# Logging to file
|
|
||||||
import logging
|
|
||||||
|
|
||||||
# Errors codes
|
|
||||||
OSC_no_error = 0
|
|
||||||
OSC_error = 1
|
|
||||||
OSC_meteobridge_auth_error = 10
|
|
||||||
OSC_meteobridge_url_error = 11
|
|
||||||
OSC_meteobridge_http_error = 12
|
|
||||||
OSC_meteobridge_nosensor_error = 20
|
|
||||||
OSC_meteobridge_restart = 30
|
|
||||||
|
|
||||||
debug_args_print = True
|
|
||||||
debug_json_print = True
|
|
||||||
debug_urllib_print = True
|
|
||||||
debug_restart_print = True
|
|
||||||
debug_osc = False
|
|
||||||
debug_working_directory = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
|
|
||||||
# define urllib timeout in seconds
|
|
||||||
url_timeout = 10
|
|
||||||
|
|
||||||
# max error number before self restart
|
|
||||||
# max_error_rst = 3
|
|
||||||
|
|
||||||
prod_flag = False
|
|
||||||
prod_working_directory = "/usr/local/com.fup.anemometre_daemon"
|
|
||||||
|
|
||||||
meteobridge_template = "cgi-bin/template.cgi?template={%22time%22:%22[DD][MM][YYYY][hh][mm][ss]%22,%22speed%22:[wind0wind-act],%22lastspeed%22:[wind0wind-lastval],%22battery%22:[wind0lowbat-act.0],%22wind-age%22:[wind0wind-age],%22signal%22:[wind0signal-act.0]}"
|
|
||||||
|
|
||||||
def main(meteobridge_url, meteobridge_user, meteobridge_passwd, max_host, max_port, errors_restart):
|
|
||||||
|
|
||||||
error_counter = 0
|
|
||||||
|
|
||||||
http_auth_status = False
|
|
||||||
|
|
||||||
oscSender = udp_client.UDPClient(max_host, max_port)
|
|
||||||
|
|
||||||
meteobridge_sensor_req = meteobridge_url + meteobridge_template
|
|
||||||
|
|
||||||
# Logging
|
|
||||||
logging.basicConfig(filename='fup_anemometer.log', encoding='utf-8', format='%(asctime)s-%(levelname)s:%(message)s', datefmt='%Y/%m/%d %H:%M:%S', level=logging.DEBUG)
|
|
||||||
logging.info("fup_anemometer started")
|
|
||||||
|
|
||||||
while True:
|
|
||||||
if http_auth_status == False:
|
|
||||||
# http log to meteobridge
|
|
||||||
passman = urllib.request.HTTPPasswordMgrWithDefaultRealm()
|
|
||||||
passman.add_password(None, meteobridge_url, meteobridge_user, meteobridge_passwd)
|
|
||||||
authhandler = urllib.request.HTTPBasicAuthHandler(passman)
|
|
||||||
opener = urllib.request.build_opener(authhandler)
|
|
||||||
urllib.request.install_opener(opener)
|
|
||||||
|
|
||||||
try:
|
|
||||||
res = urllib.request.urlopen(meteobridge_url, timeout = url_timeout)
|
|
||||||
|
|
||||||
except urllib.error.HTTPError as e:
|
|
||||||
if debug_urllib_print:
|
|
||||||
print('HTTP Error code: ', e.code)
|
|
||||||
logging.error("Authentification to " + meteobridge_url + " - HTTP Error code: " + str(e.code))
|
|
||||||
error_counter += 1
|
|
||||||
msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
|
||||||
msg.add_arg(OSC_meteobridge_http_error)
|
|
||||||
oscSender.send(msg.build())
|
|
||||||
# Sleep 5 seconds if error
|
|
||||||
time.sleep(5)
|
|
||||||
# raise SystemExit(e)
|
|
||||||
|
|
||||||
except urllib.error.URLError as e:
|
|
||||||
if debug_urllib_print:
|
|
||||||
print('URL Error Reason: ', e.reason)
|
|
||||||
logging.error("Authentification to " + meteobridge_url + " - URL Error Reason: " + str(e.reason))
|
|
||||||
error_counter += 1
|
|
||||||
msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
|
||||||
msg.add_arg(OSC_meteobridge_url_error)
|
|
||||||
oscSender.send(msg.build())
|
|
||||||
# Sleep 5 seconds if error
|
|
||||||
time.sleep(5)
|
|
||||||
# raise SystemExit(e)
|
|
||||||
|
|
||||||
else:
|
|
||||||
error_counter = 0
|
|
||||||
res_body = res.read()
|
|
||||||
if debug_urllib_print:
|
|
||||||
print(res_body.decode('utf-8'))
|
|
||||||
http_auth_status = True
|
|
||||||
logging.info("HTTP authentification to " + meteobridge_url + " succesful")
|
|
||||||
# Sleep 2 seconds if no errors
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
response = urllib.request.urlopen(meteobridge_sensor_req, timeout = url_timeout)
|
|
||||||
|
|
||||||
except urllib.error.HTTPError as e:
|
|
||||||
if debug_urllib_print:
|
|
||||||
print('HTTP Error code: ', e.code)
|
|
||||||
logging.error("Get sensor datas from : " + meteobridge_url + " - HTTP Error code: " + str(e.code))
|
|
||||||
error_counter += 1
|
|
||||||
msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
|
||||||
msg.add_arg(OSC_meteobridge_http_error)
|
|
||||||
oscSender.send(msg.build())
|
|
||||||
# Sleep 5 seconds if error
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
except urllib.error.URLError as e:
|
|
||||||
if debug_urllib_print:
|
|
||||||
print('URL Error Reason: ', e.reason)
|
|
||||||
logging.error("Get sensor datas from : " + meteobridge_url + " - URL Error Reason: " + str(e.reason))
|
|
||||||
error_counter += 1
|
|
||||||
msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
|
||||||
msg.add_arg(OSC_meteobridge_url_error)
|
|
||||||
oscSender.send(msg.build())
|
|
||||||
# Sleep 5 seconds if error
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
data_json = json.loads(response.read())
|
|
||||||
if debug_json_print == True:
|
|
||||||
print(data_json)
|
|
||||||
wind_speed = float(data_json["speed"])
|
|
||||||
wind_lastspeed = float(data_json["lastspeed"])
|
|
||||||
wind_batt = int(data_json["battery"])
|
|
||||||
wind_age = int(data_json["wind-age"])
|
|
||||||
wind_signal = int(data_json["signal"])
|
|
||||||
|
|
||||||
except json.JSONDecodeError as e:
|
|
||||||
if debug_json_print:
|
|
||||||
print("Invalid JSON syntax:", e)
|
|
||||||
logging.error("Decode JSON from : " + meteobridge_url + " - Invalid JSON syntax : " + str(e))
|
|
||||||
error_counter += 1
|
|
||||||
msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
|
||||||
msg.add_arg(OSC_meteobridge_nosensor_error)
|
|
||||||
oscSender.send(msg.build())
|
|
||||||
# Sleep 5 seconds if error
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
else:
|
|
||||||
error_counter = 0
|
|
||||||
msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/speed")
|
|
||||||
msg.add_arg(wind_lastspeed)
|
|
||||||
oscSender.send(msg.build())
|
|
||||||
|
|
||||||
msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/battery")
|
|
||||||
msg.add_arg(wind_batt)
|
|
||||||
oscSender.send(msg.build())
|
|
||||||
|
|
||||||
msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/age")
|
|
||||||
msg.add_arg(wind_age)
|
|
||||||
oscSender.send(msg.build())
|
|
||||||
|
|
||||||
msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/signal")
|
|
||||||
msg.add_arg(wind_signal)
|
|
||||||
oscSender.send(msg.build())
|
|
||||||
|
|
||||||
msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
|
||||||
msg.add_arg(OSC_no_error)
|
|
||||||
oscSender.send(msg.build())
|
|
||||||
if debug_osc:
|
|
||||||
logging.debug("OSC datas sent")
|
|
||||||
# Sleep 2 seconds if no errors
|
|
||||||
time.sleep(2)
|
|
||||||
# Self restart
|
|
||||||
if error_counter >= int(errors_restart):
|
|
||||||
msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error")
|
|
||||||
msg.add_arg(OSC_meteobridge_restart)
|
|
||||||
oscSender.send(msg.build())
|
|
||||||
time.sleep(1)
|
|
||||||
if debug_restart_print:
|
|
||||||
print("Current errors count : " + str(error_counter) + " / " + errors_restart + " max errors")
|
|
||||||
print("Too many errors restarting program ...")
|
|
||||||
logging.error("Current errors count : " + str(error_counter) + " / " + errors_restart + " max errors")
|
|
||||||
logging.error("Too many errors restarting program ...")
|
|
||||||
os.execv(sys.executable, ['python'] + sys.argv)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(description="FUP anemometer for OSC")
|
|
||||||
parser.add_argument('-url', '--url-meteobridge', default='http://192.168.0.39/')
|
|
||||||
parser.add_argument('-u', '--user-meteobridge', default='meteobridge')
|
|
||||||
parser.add_argument('-p', '--passwd-meteobridge',default='meteobridge')
|
|
||||||
parser.add_argument('-mh', '--max-host', default='localhost')
|
|
||||||
parser.add_argument('-mp','--max-port', default=2222)
|
|
||||||
parser.add_argument('-e', '--errors-restart', default=20)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
# if debug_args_print is True, print arguments
|
|
||||||
if debug_args_print:
|
|
||||||
print('Meteobridge URL:', args.url_meteobridge)
|
|
||||||
print('Meteobridge User:', args.user_meteobridge)
|
|
||||||
print('Meteobridge Password:', args.passwd_meteobridge)
|
|
||||||
print('OSC host:', args.max_host)
|
|
||||||
print('OSC port:', args.max_port)
|
|
||||||
print('Errors restart:', args.errors_restart)
|
|
||||||
|
|
||||||
main(meteobridge_url=args.url_meteobridge, meteobridge_user=args.user_meteobridge, meteobridge_passwd=args.passwd_meteobridge, max_host=args.max_host, max_port=args.max_port, errors_restart=args.errors_restart)
|
|
Loading…
Reference in New Issue
Block a user