Hi all,
I am writing a script that calculates the NDVI index and downloads the image for several dates included in a range using the Sentinel Hub Process API. To do this I am using this documentation.
The problem is that when I run the script it returns the following message:
`401 Client Error: Unauthorized for url: https://services.sentinel-hub.com/api/v1/process
Server response: “{“status”: 401, “reason”: “Unauthorized”, “message”: “You are not authorized! Please provide a valid access token within the header [Authorization: Bearer ] of your request.”, “code”: “COMMON_UNAUTHORIZED”}”`.
Does anyone have any idea what could be happening?
This is my code:
import datetime
import numpy as np
import matplotlib.pyplot as plt
from sentinelhub import (
SHConfig,
DataCollection,
SentinelHubRequest,
MosaickingOrder,
SentinelHubDownloadClient,
BBox,
bbox_to_dimensions,
CRS,
MimeType,
)
from utils import plot_image
# Se carga el perfil creado en archivo /Users/raul/.config/sentinelhub/config.toml usando las credenciales
# creadas en la cuenta de Copernicus (https://shapps.dataspace.copernicus.eu/dashboard/#/account/settings)
# Si no se ha creado antes hay que ejecutar estas líneas de aquí para hacerlo desde este código
# config = SHConfig()
# config.sh_client_id = getpass.getpass("Enter your SentinelHub client id ")
# config.sh_client_secret = getpass.getpass("Enter your SentinelHub client secret ")
# config.sh_token_url = "https://identity.dataspace.copernicus.eu/auth/realms/CDSE/protocol/openid-connect/token"
# config.sh_base_url = "https://sh.dataspace.copernicus.eu"
# config.save("ndvi")
config = SHConfig('ndvi')
# Se crea una área de interés para buscar imágenes. Se pueden obtener fácil desde http://bboxfinder.com/
aoi_coords_wgs84 = [-2.838272, 36.837645, -2.818874, 36.848532]
# Se especifica la resolución de la imagen (m) y se inicializa el bounding box (BBox)
resolution = 10
aoi_bbox = BBox(bbox=aoi_coords_wgs84, crs=CRS.WGS84)
aoi_size = bbox_to_dimensions(aoi_bbox, resolution=resolution)
start = datetime.datetime(2024, 1, 1)
end = datetime.datetime(2024, 3, 20)
n_chunks = 10
tdelta = (end - start) / n_chunks
edges = [(start + i * tdelta).date().isoformat() for i in range(n_chunks)]
slots = [(edges[i], edges[i + 1]) for i in range(len(edges) - 1)]
print('Ventanas de tiempo:')
for slot in slots:
print(slot)
# Se calcula el NDVI y se hace la petición del resultado
# Documentación y leyenda: https://custom-scripts.sentinel-hub.com/sentinel-2/ndvi/#color-legend
evalscript_ndvi = """
//VERSION=3
function setup() {
return {
input: ["B04", "B08", "dataMask"],
output: { bands: 4 }
};
}
const ramp = [
[-0.5, 0x0c0c0c],
[-0.2, 0xbfbfbf],
[-0.1, 0xdbdbdb],
[0, 0xeaeaea],
[0.025, 0xfff9cc],
[0.05, 0xede8b5],
[0.075, 0xddd89b],
[0.1, 0xccc682],
[0.125, 0xbcb76b],
[0.15, 0xafc160],
[0.175, 0xa3cc59],
[0.2, 0x91bf51],
[0.25, 0x7fb247],
[0.3, 0x70a33f],
[0.35, 0x609635],
[0.4, 0x4f892d],
[0.45, 0x3f7c23],
[0.5, 0x306d1c],
[0.55, 0x216011],
[0.6, 0x0f540a],
[1, 0x004400],
];
const visualizer = new ColorRampVisualizer(ramp);
function evaluatePixel(samples) {
let ndvi = index(samples.B08, samples.B04);
let imgVals = visualizer.process(ndvi);
return imgVals.concat(samples.dataMask)
}
"""
def get_ndvi(time_interval):
return SentinelHubRequest(
evalscript=evalscript_ndvi,
input_data=[
SentinelHubRequest.input_data(
data_collection=DataCollection.SENTINEL2_L2A,
time_interval=time_interval,
mosaicking_order=MosaickingOrder.LEAST_CC,
)
],
responses=[SentinelHubRequest.output_response("default", MimeType.TIFF)],
bbox=aoi_bbox,
size=aoi_size,
config=config,
)
# Se crea una lista de peticiones
list_of_requests = [get_ndvi(slot) for slot in slots]
list_of_requests = [request.download_list[0] for request in list_of_requests]
# Se configura la descarga de datos en varios hilos
data = SentinelHubDownloadClient(config=config).download(list_of_requests, max_threads=5)
# Se pueden mostrar las imágenes descargadas
ncols = 4
nrows = 3
aspect_ratio = aoi_size[0] / aoi_size[1]
subplot_kw = {"xticks": [], "frame_on": False}
fig, axs = plt.subplots(ncols=ncols, nrows=nrows, figsize=(5 * ncols * aspect_ratio, 5 * nrows), subplot_kw=subplot_kw)
for idx, image in enumerate(data):
ax = axs[idx // ncols][idx % ncols]
ax.imshow(np.clip(image * 2.5 / 255, 0, 1))
ax.set_title(f"{slots[idx][0]} - {slots[idx][1]}", fontsize=10)
plt.tight_layout()
And this is the detailed error:
Traceback (most recent call last):
File "/Users/raul/Documents/venvPython/.venv/lib/python3.12/site-packages/sentinelhub/download/handlers.py", line 40, in new_download_func
return download_func(self, request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/raul/Documents/venvPython/.venv/lib/python3.12/site-packages/sentinelhub/download/sentinelhub_client.py", line 95, in _execute_download
response.raise_for_status()
File "/Users/raul/Documents/venvPython/.venv/lib/python3.12/site-packages/requests/models.py", line 1021, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://services.sentinel-hub.com/api/v1/process
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/raul/Documents/descargaSentinel/descargaSentinel_v3.1_API.py", line 128, in <module>
data = SentinelHubDownloadClient(config=config).download(list_of_requests, max_threads=5)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/raul/Documents/venvPython/.venv/lib/python3.12/site-packages/sentinelhub/download/sentinelhub_client.py", line 68, in download
return super().download(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/raul/Documents/venvPython/.venv/lib/python3.12/site-packages/sentinelhub/download/client.py", line 103, in download
raise download_exception
File "/Users/raul/Documents/venvPython/.venv/lib/python3.12/site-packages/sentinelhub/download/client.py", line 100, in download
results[future_order[future]] = future.result()
^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/concurrent/futures/_base.py", line 449, in result
return self.__get_result()
^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/concurrent/futures/_base.py", line 401, in __get_result
raise self._exception
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/raul/Documents/venvPython/.venv/lib/python3.12/site-packages/sentinelhub/download/client.py", line 116, in _single_download_decoded
response = self._single_download(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/raul/Documents/venvPython/.venv/lib/python3.12/site-packages/sentinelhub/download/client.py", line 129, in _single_download
response = self._execute_download(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/raul/Documents/venvPython/.venv/lib/python3.12/site-packages/sentinelhub/download/handlers.py", line 67, in new_download_func
return download_func(self, request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/raul/Documents/venvPython/.venv/lib/python3.12/site-packages/sentinelhub/download/handlers.py", line 46, in new_download_func
raise DownloadFailedException(
sentinelhub.exceptions.DownloadFailedException: Failed to download from:
https://services.sentinel-hub.com/api/v1/process
with HTTPError:
401 Client Error: Unauthorized for url: https://services.sentinel-hub.com/api/v1/process
Server response: "{"status": 401, "reason": "Unauthorized", "message": "You are not authorized! Please provide a valid access token within the header [Authorization: Bearer <accessToken>] of your request.", "code": "COMMON_UNAUTHORIZED"}"
Greetings and thanks.