Repository: pvlib/pvlib-python

Issue:
Update CAMS/SoDa URL
SoDa has developed a new load-balancing solution, such that requests are automatically redirected to the fastest server. This means that it might be advisable for us to update the URL in the [``pvlib.iotools.get_cams``](https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.iotools.get_cams.html?highlight=get_cams#pvlib.iotools.get_cams) function. 

Email from SoDa (March 7th, 2023):
> Our beta load balancing system for SoDa/CAMS API requests is extended to March 13th. All requests made on the beta-api.soda-solardata.com WILL NOT BE COUNTED in your subscription. The beta access will last until then. **From March 14th, the service will be fully operational and you have to use api.soda-solardata.com to process your API (machine to machine) requests.**

and email from February 22nd, 2023:
> This new functionality will automatically redirect any request to the fastest available SoDa server. As a result, future updates/maintenances won't need any action from your part as server switches will be completely autonomous.

I will be following up on this issue in a couple of weeks.

*Edit: email from March 20th, 2023*
> We strongly advise you to switch your automatic commands on the load balancing system (api.soda-solardata.com). In that way, all future updates won't need any actions from your side. 


Discussion:

Patch:
diff --git a/pvlib/iotools/sodapro.py b/pvlib/iotools/sodapro.py
--- a/pvlib/iotools/sodapro.py
+++ b/pvlib/iotools/sodapro.py
@@ -9,6 +9,8 @@
 import warnings
 
 
+URL = 'api.soda-solardata.com'
+
 CAMS_INTEGRATED_COLUMNS = [
     'TOA', 'Clear sky GHI', 'Clear sky BHI', 'Clear sky DHI', 'Clear sky BNI',
     'GHI', 'BHI', 'DHI', 'BNI',
@@ -44,7 +46,7 @@
 def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
              altitude=None, time_step='1h', time_ref='UT', verbose=False,
              integrated=False, label=None, map_variables=True,
-             server='www.soda-is.com', timeout=30):
+             server=URL, timeout=30):
     """
     Retrieve time-series of radiation and/or clear-sky global, beam, and
     diffuse radiation from CAMS (see [1]_). Data is retrieved from SoDa [2]_.
@@ -91,8 +93,8 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
     map_variables: bool, default: True
         When true, renames columns of the DataFrame to pvlib variable names
         where applicable. See variable :const:`VARIABLE_MAP`.
-    server: str, default: 'www.soda-is.com'
-        Main server (www.soda-is.com) or backup mirror server (pro.soda-is.com)
+    server: str, default: :const:`pvlib.iotools.sodapro.URL`
+        Base url of the SoDa Pro CAMS Radiation API.
     timeout : int, default: 30
         Time in seconds to wait for server response before timeout
 
@@ -344,13 +346,13 @@ def read_cams(filename, integrated=False, label=None, map_variables=True):
         all time steps except for '1M' which has a default of 'right'.
     map_variables: bool, default: True
         When true, renames columns of the Dataframe to pvlib variable names
-        where applicable. See variable VARIABLE_MAP.
+        where applicable. See variable :const:`VARIABLE_MAP`.
 
     Returns
     -------
     data: pandas.DataFrame
-        Timeseries data from CAMS Radiation or McClear
-        :func:`pvlib.iotools.get_cams` for fields
+        Timeseries data from CAMS Radiation or McClear.
+        See :func:`pvlib.iotools.get_cams` for fields.
     metadata: dict
         Metadata available in the file.
 


Test patch:
diff --git a/pvlib/tests/iotools/test_sodapro.py b/pvlib/tests/iotools/test_sodapro.py
--- a/pvlib/tests/iotools/test_sodapro.py
+++ b/pvlib/tests/iotools/test_sodapro.py
@@ -209,7 +209,7 @@ def test_get_cams(requests_mock, testfile, index, columns, values, dtypes,
         mock_response = test_file.read()
     # Specify the full URI of a specific example, this ensures that all of the
     # inputs are passing on correctly
-    url_test_cams = f'https://www.soda-is.com/service/wps?DataInputs=latitude=55.7906;longitude=12.5251;altitude=80;date_begin=2020-01-01;date_end=2020-05-04;time_ref=UT;summarization=P01M;username=pvlib-admin%2540googlegroups.com;verbose=false&Service=WPS&Request=Execute&Identifier=get_{identifier}&version=1.0.0&RawDataOutput=irradiation'  # noqa: E501
+    url_test_cams = f'https://api.soda-solardata.com/service/wps?DataInputs=latitude=55.7906;longitude=12.5251;altitude=80;date_begin=2020-01-01;date_end=2020-05-04;time_ref=UT;summarization=P01M;username=pvlib-admin%2540googlegroups.com;verbose=false&Service=WPS&Request=Execute&Identifier=get_{identifier}&version=1.0.0&RawDataOutput=irradiation'  # noqa: E501
 
     requests_mock.get(url_test_cams, text=mock_response,
                       headers={'Content-Type': 'application/csv'})